/* Conversion of implicit `this' argument failed. */
if (!TYPE_P (info->from))
/* A bad conversion for 'this' must be discarding cv-quals. */
- inform (loc, " passing %qT as %<this%> "
+ inform (loc, "passing %qT as %<this%> "
"argument discards qualifiers",
from);
else
- inform (loc, " no known conversion for implicit "
+ inform (loc, "no known conversion for implicit "
"%<this%> parameter from %qH to %qI",
from, info->to_type);
}
else if (!TYPE_P (info->from))
{
if (info->n_arg >= 0)
- inform (loc, " conversion of argument %d would be ill-formed:",
+ inform (loc, "conversion of argument %d would be ill-formed:",
info->n_arg + 1);
iloc_sentinel ils = loc;
perform_implicit_conversion (info->to_type, info->from,
}
else if (info->n_arg == -2)
/* Conversion of conversion function return value failed. */
- inform (loc, " no known conversion from %qH to %qI",
+ inform (loc, "no known conversion from %qH to %qI",
from, info->to_type);
else
{
if (TREE_CODE (fn) == FUNCTION_DECL)
loc = get_fndecl_argument_location (fn, info->n_arg);
- inform (loc, " no known conversion for argument %d from %qH to %qI",
+ inform (loc, "no known conversion for argument %d from %qH to %qI",
info->n_arg + 1, from, info->to_type);
}
}
{
if (least_p)
inform_n (loc, want,
- " candidate expects at least %d argument, %d provided",
- " candidate expects at least %d arguments, %d provided",
+ "candidate expects at least %d argument, %d provided",
+ "candidate expects at least %d arguments, %d provided",
want, have);
else
inform_n (loc, want,
- " candidate expects %d argument, %d provided",
- " candidate expects %d arguments, %d provided",
+ "candidate expects %d argument, %d provided",
+ "candidate expects %d arguments, %d provided",
want, have);
}
if (fn != candidate->fn)
{
cloc = location_of (candidate->fn);
- inform (cloc, " inherited here");
+ inform (cloc, "inherited here");
}
/* Give the user some information about why this candidate failed. */
if (candidate->reason != NULL)
{
+ auto_diagnostic_nesting_level sentinel;
struct rejection_reason *r = candidate->reason;
switch (r->code)
print_conversion_rejection (cloc, &r->u.bad_conversion, fn);
break;
case rr_explicit_conversion:
- inform (cloc, " return type %qT of explicit conversion function "
+ inform (cloc, "return type %qT of explicit conversion function "
"cannot be converted to %qT with a qualification "
"conversion", r->u.conversion.from,
r->u.conversion.to_type);
break;
case rr_template_conversion:
- inform (cloc, " conversion from return type %qT of template "
+ inform (cloc, "conversion from return type %qT of template "
"conversion function specialization to %qT is not an "
"exact match", r->u.conversion.from,
r->u.conversion.to_type);
them here. */
if (r->u.template_unification.tmpl == NULL_TREE)
{
- inform (cloc, " substitution of deduced template arguments "
+ inform (cloc, "substitution of deduced template arguments "
"resulted in errors seen above");
break;
}
/* Re-run template unification with diagnostics. */
- inform (cloc, " template argument deduction/substitution failed:");
- fn_type_unification (r->u.template_unification.tmpl,
- r->u.template_unification.explicit_targs,
- (make_tree_vec
- (r->u.template_unification.num_targs)),
- r->u.template_unification.args,
- r->u.template_unification.nargs,
- r->u.template_unification.return_type,
- r->u.template_unification.strict,
- r->u.template_unification.flags,
- NULL, true, false);
+ inform (cloc, "template argument deduction/substitution failed:");
+ {
+ auto_diagnostic_nesting_level sentinel;
+ fn_type_unification (r->u.template_unification.tmpl,
+ r->u.template_unification.explicit_targs,
+ (make_tree_vec
+ (r->u.template_unification.num_targs)),
+ r->u.template_unification.args,
+ r->u.template_unification.nargs,
+ r->u.template_unification.return_type,
+ r->u.template_unification.strict,
+ r->u.template_unification.flags,
+ NULL, true, false);
+ }
break;
case rr_invalid_copy:
inform (cloc,
- " a constructor taking a single argument of its own "
+ "a constructor taking a single argument of its own "
"class type is invalid");
break;
case rr_constraint_failure:
- diagnose_constraints (cloc, fn, NULL_TREE);
+ {
+ auto_diagnostic_nesting_level sentinel;
+ diagnose_constraints (cloc, fn, NULL_TREE);
+ }
break;
case rr_inherited_ctor:
- inform (cloc, " an inherited constructor is not a candidate for "
+ inform (cloc, "an inherited constructor is not a candidate for "
"initialization from an expression of the same or derived "
"type");
break;
if (only_viable_p.is_unknown ())
only_viable_p = candidates->viable == 1;
+ auto_diagnostic_nesting_level sentinel;
+
for (; candidates; candidates = candidates->next)
{
if (only_viable_p.is_true () && candidates->viable != 1)
"passing NULL to non-pointer argument %P of %qD",
argnum, fn))
inform (get_fndecl_argument_location (fn, argnum),
- " declared here");
+ "declared here");
}
else
warning_at (loc, OPT_Wconversion_null,
"converting %<false%> to pointer type for argument "
"%P of %qD", argnum, fn))
inform (get_fndecl_argument_location (fn, argnum),
- " declared here");
+ "declared here");
}
else
warning_at (loc, OPT_Wconversion_null,
gcc_rich_location richloc (get_fndecl_argument_location (fn, argnum));
richloc.set_highlight_color (highlight_color);
inform (&richloc,
- " initializing argument %P of %qD", argnum, fn);
+ "initializing argument %P of %qD", argnum, fn);
}
}
if (diagnosing_failed_constraint::replay_errors_p ())
{
inform (loc, "the required expression %qE is invalid, because", t);
+ auto_diagnostic_nesting_level sentinel;
if (r == error_mark_node)
tsubst_expr (t, args, info.complain, info.in_decl);
else
"no operand of the disjunction is satisfied");
if (diagnosing_failed_constraint::replay_errors_p ())
{
+ auto_diagnostic_nesting_level sentinel;
/* Replay the error in each branch of the disjunction. */
auto_vec<tree_pair> operands;
collect_operands_of_disjunction (t, &operands);
disj_expr.get_start (),
disj_expr.get_finish ());
inform (loc, "the operand %qE is unsatisfied because", op);
+ auto_diagnostic_nesting_level sentinel;
satisfy_constraint_r (norm_op, args, info);
}
}
if (concepts_diagnostics_max_depth == 0)
return;
+ auto_diagnostic_nesting_level sentinel;
+
/* Replay satisfaction, but diagnose unsatisfaction. */
sat_info noisy (tf_warning_or_error, NULL_TREE, /*diag_unsat=*/true);
constraint_satisfaction_value (t, args, noisy);
cp_diagnostic_text_starter (diagnostic_text_output_format &text_output,
const diagnostic_info *diagnostic)
{
+ pp_set_prefix (text_output.get_printer (),
+ text_output.build_indent_prefix (true));
text_output.report_current_module (diagnostic_location (diagnostic));
cp_print_error_function (text_output, diagnostic);
maybe_print_instantiation_context (text_output);
if (p)
{
+ bool show_file
+ = ((!text_output.show_nesting_p ())
+ || text_output.show_locations_in_nesting_p ());
+ char *indent = text_output.build_indent_prefix (true);
pp_verbatim (text_output.get_printer (),
p->list_p ()
- ? _("%s: In substitution of %qS:\n")
- : _("%s: In instantiation of %q#D:\n"),
- LOCATION_FILE (location),
+ ? _("%s%s%sIn substitution of %qS:\n")
+ : _("%s%s%sIn instantiation of %q#D:\n"),
+ indent,
+ show_file ? LOCATION_FILE (location) : "",
+ show_file ? ": " : "",
p->get_node ());
-
+ free (indent);
location = p->locus;
p = p->next;
}
"locus", xloc.file, xloc.line);
}
+/* A RAII class for use when emitting a line of contextual information
+ via pp_verbatim to a diagnostic_text_output_format to add before/after
+ behaviors to the pp_verbatim calls.
+
+ If the text output has show_nesting_p (), then the ctor prints
+ leading indentation and a bullet point, and the dtor prints
+ the location on a new line, and calls diagnostic_show_locus, both
+ with indentation (and no bullet point).
+
+ Otherwise (when the text output has !show_nesting_p), the ctor prints
+ the location as leading information on the same line, and the
+ dtor optionally calls diagnostic_show_locus. */
+
+class auto_context_line
+{
+public:
+ auto_context_line (diagnostic_text_output_format &text_output,
+ location_t loc,
+ bool show_locus = false)
+ : m_text_output (text_output),
+ m_loc (loc),
+ m_show_locus (show_locus)
+ {
+ char *indent = m_text_output.build_indent_prefix (true);
+ pp_verbatim (m_text_output.get_printer (), indent);
+ free (indent);
+ if (!m_text_output.show_nesting_p ())
+ print_location (m_text_output, m_loc);
+ }
+ ~auto_context_line ()
+ {
+ pretty_printer *const pp = m_text_output.get_printer ();
+ if (m_text_output.show_nesting_p ())
+ {
+ if (m_text_output.show_locations_in_nesting_p ())
+ {
+ char *indent = m_text_output.build_indent_prefix (false);
+ pp_verbatim (pp, indent);
+ print_location (m_text_output, m_loc);
+ pp_newline (pp);
+
+ char *saved_prefix = pp_take_prefix (pp);
+ pp_set_prefix (pp, indent);
+ gcc_rich_location rich_loc (m_loc);
+ diagnostic_show_locus (&m_text_output.get_context (), &rich_loc,
+ DK_NOTE, pp);
+ pp_set_prefix (pp, saved_prefix);
+ }
+ }
+ else if (m_show_locus)
+ {
+ char *saved_prefix = pp_take_prefix (pp);
+ pp_set_prefix (pp, nullptr);
+ gcc_rich_location rich_loc (m_loc);
+ diagnostic_show_locus (&m_text_output.get_context (), &rich_loc,
+ DK_NOTE, pp);
+ pp_set_prefix (pp, saved_prefix);
+ }
+ }
+private:
+ diagnostic_text_output_format &m_text_output;
+ location_t m_loc;
+ bool m_show_locus;
+};
+
/* Helper function of print_instantiation_partial_context() that
prints a single line of instantiation context. */
if (loc == UNKNOWN_LOCATION)
return;
- print_location (text_output, loc);
+ auto_context_line sentinel (text_output, loc, true);
pretty_printer *const pp = text_output.get_printer ();
? _("recursively required from here\n")
: _("required from here\n"));
}
- gcc_rich_location rich_loc (loc);
- char *saved_prefix = pp_take_prefix (pp);
- diagnostic_show_locus (&text_output.get_context (), &rich_loc, DK_NOTE, pp);
- pp_set_prefix (pp, saved_prefix);
}
/* Same as print_instantiation_full_context but less verbose. */
}
if (t != NULL && skip > 0)
{
- print_location (text_output, loc);
+ auto_context_line sentinel (text_output, loc);
pp_verbatim (text_output.get_printer (),
_("[ skipping %d instantiation contexts,"
" use -ftemplate-backtrace-limit=0 to disable ]\n"),
{
const char *s = expr_as_string (t, 0);
pretty_printer *const pp = text_output.get_printer ();
- print_location (text_output, EXPR_LOCATION (t));
+ auto_context_line sentinel (text_output, EXPR_LOCATION (t));
pp_verbatim (pp,
_("in %<constexpr%> expansion of %qs"),
s);
print_constrained_decl_info (diagnostic_text_output_format &text_output,
tree decl)
{
- print_location (text_output, DECL_SOURCE_LOCATION (decl));
+ auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl));
pretty_printer *const pp = text_output.get_printer ();
pp_verbatim (pp, "required by the constraints of %q#D\n", decl);
}
tree tmpl = TREE_OPERAND (expr, 0);
- print_location (text_output, DECL_SOURCE_LOCATION (tmpl));
+ auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (tmpl));
cxx_pretty_printer *const pp
= (cxx_pretty_printer *)text_output.get_printer ();
tree src = TREE_VALUE (cxt);
if (!src)
{
- print_location (text_output, input_location);
+ auto_context_line sentinel (text_output, input_location);
pretty_printer *const pp = text_output.get_printer ();
pp_verbatim (pp, "required for constraint satisfaction\n");
return NULL_TREE;
if (map == error_mark_node)
return;
- print_location (text_output, cp_expr_loc_or_input_loc (expr));
+ auto_context_line sentinel (text_output, cp_expr_loc_or_input_loc (expr));
cxx_pretty_printer *const pp
= static_cast <cxx_pretty_printer *> (text_output.get_printer ());
pp_verbatim (pp, "in requirements ");
--- /dev/null
+// { dg-do compile { target c++17 } }
+// { dg-options "-fconcepts" }
+// { dg-additional-options "-fdiagnostics-set-output=text:experimental-nesting=yes,experimental-nesting-show-locations=no" }
+
+struct dog {};
+struct cat {};
+
+void pet(dog);
+void pet(cat);
+
+template <class T>
+concept has_member_pet = requires(T t) { t.pet(); };
+
+template <class T>
+concept has_default_pet = T::is_pettable;
+
+template <class T>
+concept pettable = has_member_pet<T> or has_default_pet<T>;
+
+void pet(pettable auto t);
+
+struct lizard {};
+
+int main() {
+ pet(lizard{}); // { dg-error "no matching function for call to 'pet\\\(lizard\\\)'" }
+}
+
+/* { dg-begin-multiline-output "" }
+ * note: candidate: 'template<class auto:1> requires pettable<auto:1> void pet(auto:1)'
+ * note: template argument deduction/substitution failed:
+ * note: constraints not satisfied
+ * In substitution of 'template<class auto:1> requires pettable<auto:1> void pet(auto:1) [with auto:1 = lizard]':
+ * required from here
+ * required for the satisfaction of 'pettable<auto:1>' [with auto:1 = lizard]
+ * note: no operand of the disjunction is satisfied
+ * note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
+ * note: candidate: 'void pet(dog)'
+ * note: no known conversion for argument 1 from 'lizard' to 'dog'
+ * note: candidate: 'void pet(cat)'
+ * note: no known conversion for argument 1 from 'lizard' to 'cat'
+ { dg-end-multiline-output "" } */
--- /dev/null
+// { dg-do compile { target c++17 } }
+// { dg-options "-fconcepts" }
+// { dg-additional-options "-fdiagnostics-set-output=text:experimental-nesting=yes,experimental-nesting-show-locations=no" }
+// { dg-additional-options "-fconcepts-diagnostics-depth=3" }
+
+struct dog {};
+struct cat {};
+
+void pet(dog);
+void pet(cat);
+
+template <class T>
+concept has_member_pet = requires(T t) { t.pet(); };
+
+template <class T>
+concept has_default_pet = T::is_pettable;
+
+template <class T>
+concept pettable = has_member_pet<T> or has_default_pet<T>;
+
+void pet(pettable auto t);
+
+struct lizard {};
+
+int main() {
+ pet(lizard{}); // { dg-error "no matching function for call to 'pet\\\(lizard\\\)'" }
+}
+
+/* { dg-begin-multiline-output "" }
+ * note: candidate: 'template<class auto:1> requires pettable<auto:1> void pet(auto:1)'
+ * note: template argument deduction/substitution failed:
+ * note: constraints not satisfied
+ * In substitution of 'template<class auto:1> requires pettable<auto:1> void pet(auto:1) [with auto:1 = lizard]':
+ * required from here
+ * required for the satisfaction of 'pettable<auto:1>' [with auto:1 = lizard]
+ * note: no operand of the disjunction is satisfied
+ * note: the operand 'has_member_pet<T>' is unsatisfied because
+ * required for the satisfaction of 'has_member_pet<T>' [with T = lizard]
+ * required for the satisfaction of 'pettable<auto:1>' [with auto:1 = lizard]
+ * in requirements with 'T t' [with T = lizard]
+ * note: the required expression 't.pet()' is invalid, because
+ * error: 'struct lizard' has no member named 'pet'
+ * note: the operand 'has_default_pet<T>' is unsatisfied because
+ * required for the satisfaction of 'has_default_pet<T>' [with T = lizard]
+ * required for the satisfaction of 'pettable<auto:1>' [with auto:1 = lizard]
+ * error: 'is_pettable' is not a member of 'lizard'
+ * note: candidate: 'void pet(dog)'
+ * note: no known conversion for argument 1 from 'lizard' to 'dog'
+ * note: candidate: 'void pet(cat)'
+ * note: no known conversion for argument 1 from 'lizard' to 'cat'
+ { dg-end-multiline-output "" } */
--- /dev/null
+// { dg-do compile { target c++17 } }
+// { dg-options "-fconcepts" }
+// { dg-additional-options "-fdiagnostics-set-output=text:experimental-nesting=yes,experimental-nesting-show-locations=no" }
+
+struct dog{};
+struct cat{};
+
+void pet(dog);
+void pet(cat);
+
+template <class T>
+concept pettable = requires(T t) { t.pet(); };
+
+template <pettable T>
+void pet(T);
+
+struct donkey {};
+
+int main() {
+ pet(donkey{}); // { dg-error "no matching function for call to 'pet\\\(donkey\\\)'" }
+}
+
+/* { dg-begin-multiline-output "" }
+ * note: candidate: 'template<class T> requires pettable<T> void pet(T)'
+ * note: template argument deduction/substitution failed:
+ * note: constraints not satisfied
+ * In substitution of 'template<class T> requires pettable<T> void pet(T) [with T = donkey]':
+ * required from here
+ * required for the satisfaction of 'pettable<T>' [with T = donkey]
+ * in requirements with 'T t' [with T = donkey]
+ * note: the required expression 't.pet()' is invalid
+ * note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
+ * note: candidate: 'void pet(dog)'
+ * note: no known conversion for argument 1 from 'donkey' to 'dog'
+ * note: candidate: 'void pet(cat)'
+ * note: no known conversion for argument 1 from 'donkey' to 'cat'
+ { dg-end-multiline-output "" } */