/* Call-backs for C++ error reporting.
This code is non-reentrant.
- Copyright (C) 1993-2017 Free Software Foundation, Inc.
+ Copyright (C) 1993-2020 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
<http://www.gnu.org/licenses/>. */
#include "config.h"
+/* For use with name_hint. */
+#define INCLUDE_UNIQUE_PTR
#include "system.h"
#include "coretypes.h"
#include "cp-tree.h"
#include "c-family/c-objc.h"
#include "ubsan.h"
#include "internal-fn.h"
+#include "gcc-rich-location.h"
+#include "cp-name-hint.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
#define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
# define NEXT_CODE(T) (TREE_CODE (TREE_TYPE (T)))
static const char *args_to_string (tree, int);
-static const char *assop_to_string (enum tree_code);
static const char *code_to_string (enum tree_code);
static const char *cv_to_string (tree, int);
static const char *decl_to_string (tree, int);
-static const char *expr_to_string (tree);
static const char *fndecl_to_string (tree, int);
-static const char *op_to_string (enum tree_code);
+static const char *op_to_string (bool, enum tree_code);
static const char *parm_to_string (int);
-static const char *type_to_string (tree, int);
+static const char *type_to_string (tree, int, bool, bool *, bool);
static void dump_alias_template_specialization (cxx_pretty_printer *, tree, int);
static void dump_type (cxx_pretty_printer *, tree, int);
static void print_instantiation_partial_context (diagnostic_context *,
struct tinst_level *,
location_t);
+static void maybe_print_constraint_context (diagnostic_context *);
static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
static bool cp_printer (pretty_printer *, text_info *, const char *,
- int, bool, bool, bool, bool, const char **);
+ int, bool, bool, bool, bool *, const char **);
/* Struct for handling %H or %I, which require delaying printing the
type until a postprocessing stage. */
-struct deferred_printed_type
+class deferred_printed_type
{
+public:
deferred_printed_type ()
: m_tree (NULL_TREE), m_buffer_ptr (NULL), m_verbose (false), m_quote (false)
{}
: m_type_a (), m_type_b ()
{}
+ format_postprocessor *clone() const FINAL OVERRIDE
+ {
+ return new cxx_format_postprocessor ();
+ }
+
void handle (pretty_printer *pp) FINAL OVERRIDE;
deferred_printed_type m_type_a;
if (scope == NULL_TREE)
return;
+ /* Enum values within an unscoped enum will be CONST_DECL with an
+ ENUMERAL_TYPE as their "scope". Use CP_TYPE_CONTEXT of the
+ ENUMERAL_TYPE, so as to print any enclosing namespace. */
+ if (UNSCOPED_ENUM_P (scope))
+ scope = CP_TYPE_CONTEXT (scope);
+
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
if (scope != global_namespace)
pp_cxx_colon_colon (pp);
}
}
- else if (AGGREGATE_TYPE_P (scope))
+ else if (AGGREGATE_TYPE_P (scope)
+ || SCOPED_ENUM_P (scope))
{
dump_type (pp, scope, f);
pp_cxx_colon_colon (pp);
pop_deferring_access_checks ();
/* Strip typedefs. We can't just use TFF_CHASE_TYPEDEF because
pp_simple_type_specifier doesn't know about it. */
- t = strip_typedefs (t);
+ t = strip_typedefs (t, NULL, STF_USER_VISIBLE);
dump_type (pp, t, TFF_PLAIN_IDENTIFIER);
}
}
static void
dump_alias_template_specialization (cxx_pretty_printer *pp, tree t, int flags)
{
- gcc_assert (alias_template_specialization_p (t));
+ gcc_assert (alias_template_specialization_p (t, nt_opaque));
tree decl = TYPE_NAME (t);
if (!(flags & TFF_UNQUALIFIED_NAME))
|| DECL_SELF_REFERENCE_P (decl)
|| (!flag_pretty_templates
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
- t = strip_typedefs (t);
- else if (alias_template_specialization_p (t))
+ {
+ unsigned int stf_flags = (!(pp->flags & pp_c_flag_gnu_v3)
+ ? STF_USER_VISIBLE : 0);
+ t = strip_typedefs (t, NULL, stf_flags);
+ }
+ else if (alias_template_specialization_p (t, nt_opaque))
{
dump_alias_template_specialization (pp, t, flags);
return;
case TEMPLATE_TYPE_PARM:
pp_cxx_cv_qualifier_seq (pp, t);
- if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
- pp_cxx_constrained_type_spec (pp, c);
+ if (template_placeholder_p (t))
+ {
+ t = TREE_TYPE (CLASS_PLACEHOLDER_TEMPLATE (t));
+ pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t));
+ pp_string (pp, "<...auto...>");
+ }
else if (TYPE_IDENTIFIER (t))
pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t));
else
pp_cxx_canonical_template_parameter
(pp, TEMPLATE_TYPE_PARM_INDEX (t));
+ /* If this is a constrained placeholder, add the requirements. */
+ if (tree c = PLACEHOLDER_TYPE_CONSTRAINTS (t))
+ pp_cxx_constrained_type_spec (pp, c);
break;
/* This is not always necessary for pointers and such, but doing this
typdef = (!DECL_ARTIFICIAL (name)
/* An alias specialization is not considered to be a
typedef. */
- && !alias_template_specialization_p (t));
+ && !alias_template_specialization_p (t, nt_opaque));
if ((typdef
&& ((flags & TFF_CHASE_TYPEDEF)
name = DECL_NAME (name);
}
- if (name == 0 || anon_aggrname_p (name))
- {
- if (flags & TFF_CLASS_KEY_OR_ENUM)
- pp_string (pp, M_("<unnamed>"));
- else
- pp_printf (pp, M_("<unnamed %s>"), variety);
- }
- else if (LAMBDA_TYPE_P (t))
+ if (LAMBDA_TYPE_P (t))
{
/* A lambda's "type" is essentially its signature. */
pp_string (pp, M_("<lambda"));
flags);
pp_greater (pp);
}
+ else if (!name || IDENTIFIER_ANON_P (name))
+ {
+ if (flags & TFF_CLASS_KEY_OR_ENUM)
+ pp_string (pp, M_("<unnamed>"));
+ else
+ pp_printf (pp, M_("<unnamed %s>"), variety);
+ }
else
pp_cxx_tree_identifier (pp, name);
+
if (tmplate)
dump_template_parms (pp, TYPE_TEMPLATE_INFO (t),
!CLASSTYPE_USE_TEMPLATE (t),
}
if (TYPE_PTR_P (t))
pp_star (pp);
- else if (TREE_CODE (t) == REFERENCE_TYPE)
- {
- if (TYPE_REF_IS_RVALUE (t))
- pp_ampersand_ampersand (pp);
- else
- pp_ampersand (pp);
- }
+ else if (TYPE_REF_P (t))
+ {
+ if (TYPE_REF_IS_RVALUE (t))
+ pp_ampersand_ampersand (pp);
+ else
+ pp_ampersand (pp);
+ }
pp->padding = pp_before;
pp_cxx_cv_qualifier_seq (pp, t);
}
static void
dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
{
+ if (template_parm_object_p (t))
+ return dump_expr (pp, DECL_INITIAL (t), flags);
+
if (flags & TFF_DECL_SPECIFIERS)
{
if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
pp_cxx_right_bracket (pp);
break;
- case ARRAY_NOTATION_REF:
- dump_decl (pp, ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS);
- pp_cxx_left_bracket (pp);
- dump_decl (pp, ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS);
- pp_colon (pp);
- dump_decl (pp, ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS);
- pp_colon (pp);
- dump_decl (pp, ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS);
- pp_cxx_right_bracket (pp);
- break;
-
/* So that we can do dump_decl on an aggr type. */
case RECORD_TYPE:
case UNION_TYPE:
dump_template_decl (pp, t, flags);
break;
+ case CONCEPT_DECL:
+ pp_cxx_ws_string (pp, "concept");
+ dump_decl_name (pp, DECL_NAME (t), flags);
+ break;
+
+ case WILDCARD_DECL:
+ pp_string (pp, "<wildcard>");
+ break;
+
case TEMPLATE_ID_EXPR:
{
tree name = TREE_OPERAND (t, 0);
else if (DECL_TEMPLATE_RESULT (t)
&& (VAR_P (DECL_TEMPLATE_RESULT (t))
/* Alias template. */
- || DECL_TYPE_TEMPLATE_P (t)))
+ || DECL_TYPE_TEMPLATE_P (t)
+ /* Concept definition. &*/
+ || TREE_CODE (DECL_TEMPLATE_RESULT (t)) == CONCEPT_DECL))
dump_decl (pp, DECL_TEMPLATE_RESULT (t), flags | TFF_TEMPLATE_NAME);
else
{
/* Add the typename without any cv-qualifiers. */
mv = TYPE_MAIN_VARIANT (*tp);
- if (TREE_CODE (*tp) == TYPE_PACK_EXPANSION)
+ if (PACK_EXPANSION_P (*tp))
{
/* Don't mess with parameter packs since we don't remember
the pack expansion context for a particular typename. */
{
if (DECL_DECLARED_CONCEPT_P (t))
pp_cxx_ws_string (pp, "concept");
- else
+ else if (DECL_IMMEDIATE_FUNCTION_P (t))
+ pp_cxx_ws_string (pp, "consteval");
+ else
pp_cxx_ws_string (pp, "constexpr");
}
}
case TEMPLATE_DECL:
case NAMESPACE_DECL:
case LABEL_DECL:
+ case WILDCARD_DECL:
case OVERLOAD:
case TYPE_DECL:
case IDENTIFIER_NODE:
dump_binary_op (pp, "+", t, flags);
break;
+ case POINTER_DIFF_EXPR:
+ dump_binary_op (pp, "-", t, flags);
+ break;
+
case INIT_EXPR:
case MODIFY_EXPR:
- dump_binary_op (pp, assignment_operator_name_info[NOP_EXPR].name,
- t, flags);
+ dump_binary_op (pp, OVL_OP_INFO (true, NOP_EXPR)->name, t, flags);
break;
case PLUS_EXPR:
case GE_EXPR:
case EQ_EXPR:
case NE_EXPR:
+ case SPACESHIP_EXPR:
case EXACT_DIV_EXPR:
- dump_binary_op (pp, operator_name_info[TREE_CODE (t)].name, t, flags);
+ dump_binary_op (pp, OVL_OP_INFO (false, TREE_CODE (t))->name, t, flags);
break;
case CEIL_DIV_EXPR:
if (!is_this_parameter (ob))
{
dump_expr (pp, ob, flags | TFF_EXPR_IN_PARENS);
- if (TREE_CODE (TREE_TYPE (ob)) == REFERENCE_TYPE)
+ if (TYPE_REF_P (TREE_TYPE (ob)))
pp_cxx_dot (pp);
else
pp_cxx_arrow (pp);
pp_cxx_right_bracket (pp);
break;
- case ARRAY_NOTATION_REF:
- dump_expr (pp, ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS);
- pp_cxx_left_bracket (pp);
- dump_expr (pp, ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS);
- pp_colon (pp);
- dump_expr (pp, ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS);
- pp_colon (pp);
- dump_expr (pp, ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS);
- pp_cxx_right_bracket (pp);
- break;
-
case UNARY_PLUS_EXPR:
dump_unary_op (pp, "+", t, flags);
break;
shouldn't print the `&' doing so indicates to the user
that the expression has pointer type. */
|| (TREE_TYPE (t)
- && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE))
+ && TYPE_REF_P (TREE_TYPE (t))))
dump_expr (pp, TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
else if (TREE_CODE (TREE_OPERAND (t, 0)) == LABEL_DECL)
dump_unary_op (pp, "&&", t, flags);
case TRUTH_NOT_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
- dump_unary_op (pp, operator_name_info [TREE_CODE (t)].name, t, flags);
+ dump_unary_op (pp, OVL_OP_INFO (false, TREE_CODE (t))->name, t, flags);
break;
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
pp_cxx_left_paren (pp);
dump_expr (pp, TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
- pp_cxx_ws_string (pp, operator_name_info[TREE_CODE (t)].name);
+ pp_cxx_ws_string (pp, OVL_OP_INFO (false, TREE_CODE (t))->name);
pp_cxx_right_paren (pp);
break;
tree optype = TREE_TYPE (op);
if (TREE_CODE (ttype) != TREE_CODE (optype)
- && POINTER_TYPE_P (ttype)
- && POINTER_TYPE_P (optype)
+ && INDIRECT_TYPE_P (ttype)
+ && INDIRECT_TYPE_P (optype)
&& same_type_p (TREE_TYPE (optype),
TREE_TYPE (ttype)))
{
- if (TREE_CODE (ttype) == REFERENCE_TYPE)
+ if (TYPE_REF_P (ttype))
{
STRIP_NOPS (op);
if (TREE_CODE (op) == ADDR_EXPR)
case REALPART_EXPR:
case IMAGPART_EXPR:
- pp_cxx_ws_string (pp, operator_name_info[TREE_CODE (t)].name);
+ pp_cxx_ws_string (pp, OVL_OP_INFO (false, TREE_CODE (t))->name);
pp_cxx_whitespace (pp);
dump_expr (pp, TREE_OPERAND (t, 0), flags);
break;
- case DEFAULT_ARG:
+ case DEFERRED_PARSE:
pp_string (pp, M_("<unparsed>"));
break;
case INTEGER_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
+ case DECLTYPE_TYPE:
pp_type_specifier_seq (pp, t);
break;
case VEC_DELETE_EXPR:
case MODOP_EXPR:
case ABS_EXPR:
+ case ABSU_EXPR:
case CONJ_EXPR:
case VECTOR_CST:
case FIXED_CST:
pp_cxx_nested_requirement (cxx_pp, t);
break;
- case PRED_CONSTR:
+ case ATOMIC_CONSTR:
case CHECK_CONSTR:
- case EXPR_CONSTR:
- case TYPE_CONSTR:
- case ICONV_CONSTR:
- case DEDUCT_CONSTR:
- case EXCEPT_CONSTR:
- case PARM_CONSTR:
case CONJ_CONSTR:
case DISJ_CONSTR:
- pp_cxx_constraint (cxx_pp, t);
- break;
+ {
+ pp_cxx_constraint (cxx_pp, t);
+ break;
+ }
case PLACEHOLDER_EXPR:
pp_string (pp, M_("*this"));
if (DECL_P (t))
return DECL_SOURCE_LOCATION (t);
- if (TREE_CODE (t) == DEFAULT_ARG)
- return defarg_location (t);
- return EXPR_LOC_OR_LOC (t, input_location);
+ if (TREE_CODE (t) == DEFERRED_PARSE)
+ return defparse_location (t);
+ return cp_expr_loc_or_input_loc (t);
}
/* Now the interfaces from error et al to dump_type et al. Each takes an
return pp_ggc_formatted_text (cxx_pp);
}
-static const char *
+const char *
expr_to_string (tree decl)
{
reinit_cxx_pp ();
}
static const char *
-op_to_string (enum tree_code p)
+op_to_string (bool assop, enum tree_code p)
{
- tree id = operator_name_info[p].identifier;
+ tree id = ovl_op_identifier (assop, p);
return id ? IDENTIFIER_POINTER (id) : M_("<unknown>");
}
+/* Return a GC-allocated representation of type TYP, with verbosity VERBOSE.
+
+ If QUOTE is non-NULL and if *QUOTE is true, then quotes are added to the
+ string in appropriate places, and *QUOTE is written to with false
+ to suppress pp_format's trailing close quote so that e.g.
+ foo_typedef {aka underlying_foo} {enum}
+ can be printed by "%qT" as:
+ `foo_typedef' {aka `underlying_foo'} {enum}
+ rather than:
+ `foo_typedef {aka underlying_foo} {enum}'
+ When adding such quotes, if POSTPROCESSED is true (for handling %H and %I)
+ then a leading open quote will be added, whereas if POSTPROCESSED is false
+ (for handling %T) then any leading quote has already been added by
+ pp_format, or is not needed due to QUOTE being NULL (for template arguments
+ within %H and %I).
+
+ SHOW_COLOR is used to determine the colorization of any quotes that
+ are added. */
+
static const char *
-type_to_string (tree typ, int verbose)
+type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
+ bool show_color)
{
int flags = 0;
if (verbose)
flags |= TFF_TEMPLATE_HEADER;
reinit_cxx_pp ();
+
+ if (postprocessed && quote && *quote)
+ pp_begin_quote (cxx_pp, show_color);
+
+ struct obstack *ob = pp_buffer (cxx_pp)->obstack;
+ int type_start, type_len;
+ type_start = obstack_object_size (ob);
+
dump_type (cxx_pp, typ, flags);
+
+ /* Remember the end of the initial dump. */
+ type_len = obstack_object_size (ob) - type_start;
+
/* If we're printing a type that involves typedefs, also print the
stripped version. But sometimes the stripped version looks
exactly the same, so we don't want it after all. To avoid printing
&& !uses_template_parms (typ))
{
int aka_start, aka_len; char *p;
- struct obstack *ob = pp_buffer (cxx_pp)->obstack;
- /* Remember the end of the initial dump. */
- int len = obstack_object_size (ob);
- tree aka = strip_typedefs (typ);
+ tree aka = strip_typedefs (typ, NULL, STF_USER_VISIBLE);
+ if (quote && *quote)
+ pp_end_quote (cxx_pp, show_color);
pp_string (cxx_pp, " {aka");
pp_cxx_whitespace (cxx_pp);
+ if (quote && *quote)
+ pp_begin_quote (cxx_pp, show_color);
/* And remember the start of the aka dump. */
aka_start = obstack_object_size (ob);
dump_type (cxx_pp, aka, flags);
aka_len = obstack_object_size (ob) - aka_start;
+ if (quote && *quote)
+ pp_end_quote (cxx_pp, show_color);
pp_right_brace (cxx_pp);
p = (char*)obstack_base (ob);
- /* If they are identical, cut off the aka with a NUL. */
- if (len == aka_len && memcmp (p, p+aka_start, len) == 0)
- p[len] = '\0';
+ /* If they are identical, cut off the aka by unwinding the obstack. */
+ if (type_len == aka_len
+ && memcmp (p + type_start, p+aka_start, type_len) == 0)
+ {
+ /* We can't add a '\0' here, since we may be adding a closing quote
+ below, and it would be hidden by the '\0'.
+ Instead, manually unwind the current object within the obstack
+ so that the insertion point is at the end of the type, before
+ the "' {aka". */
+ int delta = type_start + type_len - obstack_object_size (ob);
+ gcc_assert (delta <= 0);
+ obstack_blank_fast (ob, delta);
+ }
+ else
+ if (quote)
+ /* No further closing quotes are needed. */
+ *quote = false;
}
- return pp_ggc_formatted_text (cxx_pp);
-}
-static const char *
-assop_to_string (enum tree_code p)
-{
- tree id = assignment_operator_name_info[(int) p].identifier;
- return id ? IDENTIFIER_POINTER (id) : M_("{unknown}");
+ if (quote && *quote)
+ {
+ pp_end_quote (cxx_pp, show_color);
+ *quote = false;
+ }
+ return pp_ggc_formatted_text (cxx_pp);
}
static const char *
reinit_cxx_pp ();
for (; p; p = TREE_CHAIN (p))
{
- if (TREE_VALUE (p) == null_node)
+ if (null_node_p (TREE_VALUE (p)))
pp_cxx_ws_string (cxx_pp, "NULL");
else
dump_type (cxx_pp, error_type (TREE_VALUE (p)), flags);
cxx_print_error_function (diagnostic_context *context, const char *file,
diagnostic_info *diagnostic)
{
+ char *prefix;
+ if (file)
+ prefix = xstrdup (file);
+ else
+ prefix = NULL;
lhd_print_error_function (context, file, diagnostic);
- pp_set_prefix (context->printer, file);
+ pp_set_prefix (context->printer, prefix);
maybe_print_instantiation_context (context);
}
cp_print_error_function (context, diagnostic);
maybe_print_instantiation_context (context);
maybe_print_constexpr_context (context);
+ maybe_print_constraint_context (context);
pp_set_prefix (context->printer, diagnostic_build_prefix (context,
diagnostic));
}
to be wrong, so just rely on print_instantiation_full_context. */
if (current_instantiation ())
return;
+ /* The above is true for constraint satisfaction also. */
+ if (current_failed_constraint)
+ return;
if (diagnostic_last_function_changed (context, diagnostic))
{
- const char *old_prefix = context->printer->prefix;
+ char *old_prefix = pp_take_prefix (context->printer);
const char *file = LOCATION_FILE (diagnostic_location (diagnostic));
tree abstract_origin = diagnostic_abstract_origin (diagnostic);
char *new_prefix = (file && abstract_origin == NULL)
if (abstract_origin)
{
ao = BLOCK_ABSTRACT_ORIGIN (abstract_origin);
- while (TREE_CODE (ao) == BLOCK
- && BLOCK_ABSTRACT_ORIGIN (ao)
- && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
- ao = BLOCK_ABSTRACT_ORIGIN (ao);
gcc_assert (TREE_CODE (ao) == FUNCTION_DECL);
fndecl = ao;
}
&& BLOCK_ABSTRACT_ORIGIN (block))
{
ao = BLOCK_ABSTRACT_ORIGIN (block);
-
- while (TREE_CODE (ao) == BLOCK
- && BLOCK_ABSTRACT_ORIGIN (ao)
- && BLOCK_ABSTRACT_ORIGIN (ao) != ao)
- ao = BLOCK_ABSTRACT_ORIGIN (ao);
-
if (TREE_CODE (ao) == FUNCTION_DECL)
{
fndecl = ao;
if (p)
{
pp_verbatim (context->printer,
- TREE_CODE (p->decl) == TREE_LIST
+ p->list_p ()
? _("%s: In substitution of %qS:\n")
: _("%s: In instantiation of %q#D:\n"),
LOCATION_FILE (location),
- p->decl);
+ p->get_node ());
location = p->locus;
p = p->next;
static void
print_instantiation_partial_context_line (diagnostic_context *context,
- const struct tinst_level *t,
+ struct tinst_level *t,
location_t loc, bool recursive_p)
{
if (loc == UNKNOWN_LOCATION)
if (t != NULL)
{
- if (TREE_CODE (t->decl) == TREE_LIST)
+ if (t->list_p ())
pp_verbatim (context->printer,
recursive_p
? _("recursively required by substitution of %qS\n")
: _("required by substitution of %qS\n"),
- t->decl);
+ t->get_node ());
else
pp_verbatim (context->printer,
recursive_p
? _("recursively required from %q#D\n")
: _("required from %q#D\n"),
- t->decl);
+ t->get_node ());
}
else
{
const char *s = expr_as_string (t, 0);
if (context->show_column)
pp_verbatim (context->printer,
- _("%r%s:%d:%d:%R in constexpr expansion of %qs"),
+ _("%r%s:%d:%d:%R in %<constexpr%> expansion of %qs"),
"locus", xloc.file, xloc.line, xloc.column, s);
else
pp_verbatim (context->printer,
- _("%r%s:%d:%R in constexpr expansion of %qs"),
+ _("%r%s:%d:%R in %<constexpr%> expansion of %qs"),
"locus", xloc.file, xloc.line, s);
pp_newline (context->printer);
}
}
\f
+static void
+print_location (diagnostic_context *context, location_t loc)
+{
+ expanded_location xloc = expand_location (loc);
+ if (context->show_column)
+ pp_verbatim (context->printer, _("%r%s:%d:%d:%R "),
+ "locus", xloc.file, xloc.line, xloc.column);
+ else
+ pp_verbatim (context->printer, _("%r%s:%d:%R "),
+ "locus", xloc.file, xloc.line);
+}
+
+/* Instantiate the concept check for the purpose of diagnosing an error. */
+
+static tree
+rebuild_concept_check (tree expr, tree map, tree args)
+{
+ /* Instantiate the parameter mapping for the template-id. */
+ map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
+ if (map == error_mark_node)
+ return error_mark_node;
+ args = get_mapped_args (map);
+
+ /* Rebuild the template id using substituted arguments. Substituting
+ directly through the expression will trigger recursive satisfaction,
+ so don't do that. */
+ tree id = unpack_concept_check (expr);
+ args = tsubst_template_args (TREE_OPERAND (id, 1), args, tf_none, NULL_TREE);
+ if (args == error_mark_node)
+ return error_mark_node;
+ return build_nt (TEMPLATE_ID_EXPR, TREE_OPERAND (id, 0), args);
+}
+
+static void
+print_constrained_decl_info (diagnostic_context *context, tree decl)
+{
+ print_location (context, DECL_SOURCE_LOCATION (decl));
+ pp_verbatim (context->printer, "required by the constraints of %q#D\n", decl);
+}
+
+static void
+print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree args)
+{
+ gcc_assert (concept_check_p (expr));
+
+ tree id = unpack_concept_check (expr);
+ tree tmpl = TREE_OPERAND (id, 0);
+ if (OVL_P (tmpl))
+ tmpl = OVL_FIRST (tmpl);
+ tree check = rebuild_concept_check (expr, map, args);
+ if (check == error_mark_node)
+ check = expr;
+
+ print_location (context, DECL_SOURCE_LOCATION (tmpl));
+ pp_verbatim (context->printer, "required for the satisfaction of %qE\n", check);
+}
+
+/* Diagnose the entry point into the satisfaction error. Returns the next
+ context, if any. */
+
+static tree
+print_constraint_context_head (diagnostic_context *context, tree cxt, tree args)
+{
+ tree src = TREE_VALUE (cxt);
+ if (!src)
+ {
+ print_location (context, input_location);
+ pp_verbatim (context->printer, "required for constraint satisfaction\n");
+ return NULL_TREE;
+ }
+ if (DECL_P (src))
+ {
+ print_constrained_decl_info (context, src);
+ return NULL_TREE;
+ }
+ else
+ {
+ print_concept_check_info (context, src, TREE_PURPOSE (cxt), args);
+ return TREE_CHAIN (cxt);
+ }
+}
+
+static void
+print_requires_expression_info (diagnostic_context *context, tree constr, tree args)
+{
+
+ tree expr = ATOMIC_CONSTR_EXPR (constr);
+ tree map = ATOMIC_CONSTR_MAP (constr);
+ map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
+ if (map == error_mark_node)
+ return;
+ args = get_mapped_args (map);
+
+ print_location (context, cp_expr_loc_or_input_loc (expr));
+ pp_verbatim (context->printer, "in requirements ");
+
+ tree parms = TREE_OPERAND (expr, 0);
+ if (parms)
+ pp_verbatim (context->printer, "with ");
+ while (parms)
+ {
+ tree next = TREE_CHAIN (parms);
+
+ TREE_CHAIN (parms) = NULL_TREE;
+ cp_unevaluated u;
+ tree p = tsubst (parms, args, tf_none, NULL_TREE);
+ pp_verbatim (context->printer, "%q#D", p);
+ TREE_CHAIN (parms) = next;
+
+ if (next)
+ pp_separate_with_comma ((cxx_pretty_printer *)context->printer);
+
+ parms = next;
+ }
+
+ pp_verbatim (context->printer, "\n");
+}
+
+void
+maybe_print_single_constraint_context (diagnostic_context *context, tree failed)
+{
+ if (!failed)
+ return;
+
+ tree constr = TREE_VALUE (failed);
+ if (!constr || constr == error_mark_node)
+ return;
+ tree cxt = CONSTR_CONTEXT (constr);
+ if (!cxt)
+ return;
+ tree args = TREE_PURPOSE (failed);
+
+ /* Print the stack of requirements. */
+ cxt = print_constraint_context_head (context, cxt, args);
+ while (cxt && !DECL_P (TREE_VALUE (cxt)))
+ {
+ tree expr = TREE_VALUE (cxt);
+ tree map = TREE_PURPOSE (cxt);
+ print_concept_check_info (context, expr, map, args);
+ cxt = TREE_CHAIN (cxt);
+ }
+
+ /* For certain constraints, we can provide additional context. */
+ if (TREE_CODE (constr) == ATOMIC_CONSTR
+ && TREE_CODE (ATOMIC_CONSTR_EXPR (constr)) == REQUIRES_EXPR)
+ print_requires_expression_info (context, constr, args);
+}
+
+void
+maybe_print_constraint_context (diagnostic_context *context)
+{
+ if (!current_failed_constraint)
+ return;
+
+ tree cur = current_failed_constraint;
+
+ /* Recursively print nested contexts. */
+ current_failed_constraint = TREE_CHAIN (current_failed_constraint);
+ if (current_failed_constraint)
+ maybe_print_constraint_context (context);
+
+ /* Print this context. */
+ maybe_print_single_constraint_context (context, cur);
+}
+
/* Return true iff TYPE_A and TYPE_B are template types that are
meaningful to compare. */
arg_to_string (tree arg, bool verbose)
{
if (TYPE_P (arg))
- return type_to_string (arg, verbose);
+ return type_to_string (arg, verbose, true, NULL, false);
else
return expr_to_string (arg);
}
}
else
{
- /* If the types were not comparable, they are printed normally,
- and no difference tree is printed. */
- type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose);
- type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose);
+ /* If the types were not comparable (or if only one of %H/%I was
+ provided), they are printed normally, and no difference tree
+ is printed. */
+ type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose,
+ true, &type_a.m_quote, show_color);
+ type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose,
+ true, &type_b.m_quote, show_color);
}
if (type_a.m_quote)
%D declaration.
%E expression.
%F function declaration.
+ %G gcall *
+ %H type difference (from).
+ %I type difference (to).
+ %K tree
%L language as used in extern "lang".
%O binary operator.
%P function parameter whose position is indicated by an integer.
%S substitution (template + args)
%T type.
%V cv-qualifier.
- %X exception-specification.
- %H type difference (from)
- %I type difference (to). */
+ %X exception-specification. */
static bool
cp_printer (pretty_printer *pp, text_info *text, const char *spec,
int precision, bool wide, bool set_locus, bool verbose,
- bool quoted, const char **buffer_ptr)
+ bool *quoted, const char **buffer_ptr)
{
gcc_assert (pp->m_format_postprocessor);
cxx_format_postprocessor *postprocessor
break;
case 'E': result = expr_to_string (next_tree); break;
case 'F': result = fndecl_to_string (next_tree, verbose); break;
- case 'L': result = language_to_string (next_lang); break;
- case 'O': result = op_to_string (next_tcode); break;
- case 'P': result = parm_to_string (next_int); break;
- case 'Q': result = assop_to_string (next_tcode); break;
- case 'S': result = subst_to_string (next_tree); break;
- case 'T': result = type_to_string (next_tree, verbose); break;
- case 'V': result = cv_to_string (next_tree, verbose); break;
- case 'X': result = eh_spec_to_string (next_tree, verbose); break;
-
case 'G':
percent_G_format (text);
return true;
-
+ case 'H':
+ defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree,
+ buffer_ptr, verbose, *quoted);
+ return true;
+ case 'I':
+ defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree,
+ buffer_ptr, verbose, *quoted);
+ return true;
case 'K':
t = va_arg (*text->args_ptr, tree);
- percent_K_format (text, t);
+ percent_K_format (text, EXPR_LOCATION (t), TREE_BLOCK (t));
return true;
-
- case 'H':
- {
- defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree,
- buffer_ptr, verbose, quoted);
- return true;
- }
-
- case 'I':
+ case 'L': result = language_to_string (next_lang); break;
+ case 'O': result = op_to_string (false, next_tcode); break;
+ case 'P': result = parm_to_string (next_int); break;
+ case 'Q': result = op_to_string (true, next_tcode); break;
+ case 'S': result = subst_to_string (next_tree); break;
+ case 'T':
{
- defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree,
- buffer_ptr, verbose, quoted);
- return true;
+ result = type_to_string (next_tree, verbose, false, quoted,
+ pp_show_color (pp));
}
+ break;
+ case 'V': result = cv_to_string (next_tree, verbose); break;
+ case 'X': result = eh_spec_to_string (next_tree, verbose); break;
default:
return false;
pp_string (pp, result);
if (set_locus && t != NULL)
- text->set_location (0, location_of (t), true);
+ text->set_location (0, location_of (t), SHOW_RANGE_WITH_CARET);
return true;
#undef next_tree
#undef next_tcode
void
maybe_warn_cpp0x (cpp0x_warn_str str)
{
- if ((cxx_dialect == cxx98) && !in_system_header_at (input_location))
- /* We really want to suppress this warning in system headers,
- because libstdc++ uses variadic templates even when we aren't
- in C++0x mode. */
+ if (cxx_dialect == cxx98)
switch (str)
{
case CPP0X_INITIALIZER_LISTS:
pedwarn (input_location, 0,
"extended initializer lists "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_EXPLICIT_CONVERSION:
pedwarn (input_location, 0,
"explicit conversion operators "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_VARIADIC_TEMPLATES:
pedwarn (input_location, 0,
"variadic templates "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_LAMBDA_EXPR:
pedwarn (input_location, 0,
"lambda expressions "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_AUTO:
pedwarn (input_location, 0,
- "C++11 auto only available with -std=c++11 or -std=gnu++11");
+ "C++11 auto only available with %<-std=c++11%> or "
+ "%<-std=gnu++11%>");
break;
case CPP0X_SCOPED_ENUMS:
pedwarn (input_location, 0,
- "scoped enums only available with -std=c++11 or -std=gnu++11");
+ "scoped enums only available with %<-std=c++11%> or "
+ "%<-std=gnu++11%>");
break;
case CPP0X_DEFAULTED_DELETED:
pedwarn (input_location, 0,
"defaulted and deleted functions "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_INLINE_NAMESPACES:
pedwarn (input_location, OPT_Wpedantic,
"inline namespaces "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_OVERRIDE_CONTROLS:
pedwarn (input_location, 0,
"override controls (override/final) "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_NSDMI:
pedwarn (input_location, 0,
"non-static data member initializers "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_USER_DEFINED_LITERALS:
pedwarn (input_location, 0,
"user-defined literals "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_DELEGATING_CTORS:
pedwarn (input_location, 0,
"delegating constructors "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_INHERITING_CTORS:
pedwarn (input_location, 0,
"inheriting constructors "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_ATTRIBUTES:
pedwarn (input_location, 0,
"c++11 attributes "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
case CPP0X_REF_QUALIFIER:
pedwarn (input_location, 0,
"ref-qualifiers "
- "only available with -std=c++11 or -std=gnu++11");
+ "only available with %<-std=c++11%> or %<-std=gnu++11%>");
break;
default:
gcc_unreachable ();
print_candidates (decl);
}
else
- error_at (location, "%qD is not a member of %qT", name, scope);
+ {
+ name_hint hint;
+ if (SCOPED_ENUM_P (scope) && TREE_CODE (name) == IDENTIFIER_NODE)
+ hint = suggest_alternative_in_scoped_enum (name, scope);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "%qD is not a member of %qT; did you mean %qs?",
+ name, scope, suggestion);
+ }
+ else
+ error_at (location, "%qD is not a member of %qT", name, scope);
+ }
}
else if (scope != global_namespace)
{
- error_at (location, "%qD is not a member of %qD", name, scope);
- if (!suggest_alternative_in_explicit_scope (location, name, scope))
- suggest_alternatives_for (location, name, false);
+ auto_diagnostic_group d;
+ bool emit_fixit = true;
+ name_hint hint
+ = suggest_alternative_in_explicit_scope (location, name, scope);
+ if (!hint)
+ {
+ hint = suggest_alternatives_in_other_namespaces (location, name);
+ /* "location" is just the location of the name, not of the explicit
+ scope, and it's not easy to get at the latter, so we can't issue
+ fix-it hints for the suggestion. */
+ emit_fixit = false;
+ }
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (location);
+ if (emit_fixit)
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc, "%qD is not a member of %qD; did you mean %qs?",
+ name, scope, suggestion);
+ }
+ else
+ error_at (location, "%qD is not a member of %qD", name, scope);
}
else
{
- error_at (location, "%<::%D%> has not been declared", name);
- suggest_alternatives_for (location, name, true);
+ auto_diagnostic_group d;
+ name_hint hint = suggest_alternatives_for (location, name, true);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "%<::%D%> has not been declared; did you mean %qs?",
+ name, suggestion);
+ }
+ else
+ error_at (location, "%<::%D%> has not been declared", name);
}
}
+
+/* C++-specific implementation of range_label::get_text () vfunc for
+ range_label_for_type_mismatch.
+
+ Compare with print_template_differences above. */
+
+label_text
+range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
+{
+ if (m_labelled_type == NULL_TREE)
+ return label_text::borrow (NULL);
+
+ const bool verbose = false;
+ const bool show_color = false;
+
+ const char *result;
+ if (m_other_type
+ && comparable_template_types_p (m_labelled_type, m_other_type))
+ result = type_to_string_with_compare (m_labelled_type, m_other_type,
+ verbose, show_color);
+ else
+ result = type_to_string (m_labelled_type, verbose, true, NULL, show_color);
+
+ /* Both of the above return GC-allocated buffers, so the caller mustn't
+ free them. */
+ return label_text::borrow (result);
+}