/* Call-backs for C++ error reporting.
This code is non-reentrant.
- Copyright (C) 1993-2018 Free Software Foundation, Inc.
+ Copyright (C) 1993-2019 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
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 *);
/* 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)
{}
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),
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
{
{
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:
case GE_EXPR:
case EQ_EXPR:
case NE_EXPR:
+ case SPACESHIP_EXPR:
case EXACT_DIV_EXPR:
dump_binary_op (pp, OVL_OP_INFO (false, TREE_CODE (t))->name, t, flags);
break;
dump_expr (pp, TREE_OPERAND (t, 0), flags);
break;
- case DEFAULT_ARG:
+ case DEFERRED_PARSE:
pp_string (pp, M_("<unparsed>"));
break;
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 cp_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
&& !uses_template_parms (typ))
{
int aka_start, aka_len; char *p;
- 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");
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))
{
char *old_prefix = pp_take_prefix (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. */
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)
{