Message ID | 20200318192115.1615832-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Include the constraint parameter mapping in diagnostic constraint contexts | expand |
On Wed, 18 Mar 2020, Patrick Palka wrote: > When diagnosing a constraint error, we currently try to print the constraint > inside a diagnostic constraint context with its template arguments substituted > in. If substitution fails, then we instead just print the dependent > form, as in the the test case below: > > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: error: static assertion failed > 14 | static_assert(E<int>); // { dg-error "static assertion failed|not a class" } > | ^~~~~~ > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: note: constraints not satisfied > gcc/testsuite/g++.dg/concepts/diagnostic6.C:4:11: required for the satisfaction of ‘C<T>’ > gcc/testsuite/g++.dg/concepts/diagnostic6.C:8:11: required for the satisfaction of ‘D<typename T::type>’ > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: error: ‘int’ is not a class, struct, or union type > > But printing just the dependent form sometimes makes it difficult to decipher > the diagnostic. In the above example, for instance, there's no indication of > how the template argument 'int' relates to either of the 'T's. > > This patch improves the situation by changing these diagnostics to always print > the dependent form of the constraint, and alongside it the (preferably > substituted) constraint parameter mapping. So with the same test case below we > now get: > > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: error: static assertion failed > 14 | static_assert(E<int>); // { dg-error "static assertion failed|not a class" } > | ^~~~~~ > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: note: constraints not satisfied > gcc/testsuite/g++.dg/concepts/diagnostic6.C:4:11: required for the satisfaction of ‘C<T>’ [with T = typename T::type] > gcc/testsuite/g++.dg/concepts/diagnostic6.C:8:11: required for the satisfaction of ‘D<typename T::type>’ [with T = int] > gcc/testsuite/g++.dg/concepts/diagnostic6.C:14:15: error: ‘int’ is not a class, struct, or union type > > This change arguably makes it easier to figure out what's going on whenever a > constraint fails due to substitution resulting in an invalid type rather than > failing due to the constraint evaluating to false. > > Tested on x86_64-pc-linux-gnu, does this look reasonable? I'm not sure if > printing an unsubstituted parameter mapping (like in the line 4 message above) > is always useful, but perhaps it's better than nothing? > Ah sorry, this is an old version of the patch. Please consider this one instead: -- >8 -- gcc/cp/ChangeLog: * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. * error.c (rebuild_concept_check): Delete. (print_concept_check_info): Print the dependent form of the constraint and the preferably substituted parameter mapping alongside it. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic6.C: New test. --- gcc/cp/cxx-pretty-print.c | 2 +- gcc/cp/cxx-pretty-print.h | 1 + gcc/cp/error.c | 41 ++++++++------------- gcc/testsuite/g++.dg/concepts/diagnostic6.C | 14 +++++++ 4 files changed, 32 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic6.C diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 100154e400f..1e89c3f9033 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2878,7 +2878,7 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t) /* Output the "[with ...]" clause for a parameter mapping of an atomic constraint. */ -static void +void pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) { for (tree p = map; p; p = TREE_CHAIN (p)) diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index 7c7347f57ba..494f3fdde59 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -112,5 +112,6 @@ void pp_cxx_conjunction (cxx_pretty_printer *, tree); void pp_cxx_disjunction (cxx_pretty_printer *, tree); void pp_cxx_constraint (cxx_pretty_printer *, tree); void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree); +void pp_cxx_parameter_mapping (cxx_pretty_printer *, tree); #endif /* GCC_CXX_PRETTY_PRINT_H */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index cc51b6ffe13..fc08558e9b6 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3680,27 +3680,6 @@ print_location (diagnostic_context *context, location_t loc) "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) { @@ -3717,12 +3696,24 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree 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); + + cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer; + pp_verbatim (pp, "required for the satisfaction of %qE", expr); + tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); + if (subst_map != error_mark_node) + map = subst_map; + if (map) + { + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + pp_cxx_parameter_mapping (pp, map); + pp_cxx_right_bracket (pp); + } + pp_newline (pp); } /* Diagnose the entry point into the satisfaction error. Returns the next diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic6.C b/gcc/testsuite/g++.dg/concepts/diagnostic6.C new file mode 100644 index 00000000000..06b17caccbe --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic6.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++2a } } + +template<typename T> + concept C = requires (T t) { t + 0; }; +// { dg-message "satisfaction of .C<T>. .with T = typename T::type." "" { target *-*-* } .-1 } + +template<typename T> + concept D = C<T>; +// { dg-message "satisfaction of .D<typename T::type>. .with T = int." "" { target *-*-* } .-1 } + +template<typename T> + concept E = D<typename T::type>; + +static_assert(E<int>); // { dg-error "static assertion failed|not a class" }
On 3/18/20 3:26 PM, Patrick Palka wrote: > + if (map) > + { > + pp_cxx_whitespace (pp); > + pp_cxx_left_bracket (pp); > + pp->translate_string ("with"); > + pp_cxx_whitespace (pp); > + pp_cxx_parameter_mapping (pp, map); > + pp_cxx_right_bracket (pp); > + } Perhaps we should move the [with ] bits into pp_cxx_parameter_mapping rather than duplicate them here. Jason
On Thu, 19 Mar 2020, Jason Merrill wrote: > On 3/18/20 3:26 PM, Patrick Palka wrote: > > + if (map) > > + { > > + pp_cxx_whitespace (pp); > > + pp_cxx_left_bracket (pp); > > + pp->translate_string ("with"); > > + pp_cxx_whitespace (pp); > > + pp_cxx_parameter_mapping (pp, map); > > + pp_cxx_right_bracket (pp); > > + } > > Perhaps we should move the [with ] bits into pp_cxx_parameter_mapping rather > than duplicate them here. Like this? -- >8 -- gcc/cp/ChangeLog: * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. Move the "[with ]" bits to here from ... (pp_cxx_atomic_constraint): ... here. * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. * error.c (rebuild_concept_check): Delete. (print_concept_check_info): Print the dependent form of the constraint and the preferably substituted parameter mapping alongside it. gcc/testsuite/ChangeLog: * g++.dg/concepts/diagnostic6.C: New test. --- gcc/cp/cxx-pretty-print.c | 12 ++++--- gcc/cp/cxx-pretty-print.h | 1 + gcc/cp/error.c | 36 +++++++-------------- gcc/testsuite/g++.dg/concepts/diagnostic6.C | 14 ++++++++ 4 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic6.C diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 100154e400f..15d8b7eb609 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2878,9 +2878,13 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t) /* Output the "[with ...]" clause for a parameter mapping of an atomic constraint. */ -static void +void pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) { + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + for (tree p = map; p; p = TREE_CHAIN (p)) { tree parm = TREE_VALUE (p); @@ -2903,6 +2907,8 @@ pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) if (TREE_CHAIN (p) != NULL_TREE) pp_cxx_separate_with (pp, ';'); } + + pp_cxx_right_bracket (pp); } void @@ -2915,12 +2921,8 @@ pp_cxx_atomic_constraint (cxx_pretty_printer *pp, tree t) tree map = ATOMIC_CONSTR_MAP (t); if (map && map != error_mark_node) { - pp_cxx_whitespace (pp); - pp_cxx_left_bracket (pp); - pp->translate_string ("with"); pp_cxx_whitespace (pp); pp_cxx_parameter_mapping (pp, map); - pp_cxx_right_bracket (pp); } } diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index 7c7347f57ba..494f3fdde59 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -112,5 +112,6 @@ void pp_cxx_conjunction (cxx_pretty_printer *, tree); void pp_cxx_disjunction (cxx_pretty_printer *, tree); void pp_cxx_constraint (cxx_pretty_printer *, tree); void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree); +void pp_cxx_parameter_mapping (cxx_pretty_printer *, tree); #endif /* GCC_CXX_PRETTY_PRINT_H */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index cc51b6ffe13..9f19e9bbaa4 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3680,27 +3680,6 @@ print_location (diagnostic_context *context, location_t loc) "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) { @@ -3717,12 +3696,19 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree 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); + + cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer; + pp_verbatim (pp, "required for the satisfaction of %qE", expr); + if (map) + { + tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); + pp_cxx_whitespace (pp); + pp_cxx_parameter_mapping (pp, (subst_map != error_mark_node + ? subst_map : map)); + } + pp_newline (pp); } /* Diagnose the entry point into the satisfaction error. Returns the next diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic6.C b/gcc/testsuite/g++.dg/concepts/diagnostic6.C new file mode 100644 index 00000000000..06b17caccbe --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic6.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++2a } } + +template<typename T> + concept C = requires (T t) { t + 0; }; +// { dg-message "satisfaction of .C<T>. .with T = typename T::type." "" { target *-*-* } .-1 } + +template<typename T> + concept D = C<T>; +// { dg-message "satisfaction of .D<typename T::type>. .with T = int." "" { target *-*-* } .-1 } + +template<typename T> + concept E = D<typename T::type>; + +static_assert(E<int>); // { dg-error "static assertion failed|not a class" }
On 3/19/20 12:50 PM, Patrick Palka wrote: > On Thu, 19 Mar 2020, Jason Merrill wrote: > >> On 3/18/20 3:26 PM, Patrick Palka wrote: >>> + if (map) >>> + { >>> + pp_cxx_whitespace (pp); >>> + pp_cxx_left_bracket (pp); >>> + pp->translate_string ("with"); >>> + pp_cxx_whitespace (pp); >>> + pp_cxx_parameter_mapping (pp, map); >>> + pp_cxx_right_bracket (pp); >>> + } >> >> Perhaps we should move the [with ] bits into pp_cxx_parameter_mapping rather >> than duplicate them here. > > Like this? > > -- >8 -- > > gcc/cp/ChangeLog: > > * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. Move > the "[with ]" bits to here from ... > (pp_cxx_atomic_constraint): ... here. > * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. > * error.c (rebuild_concept_check): Delete. > (print_concept_check_info): Print the dependent form of the constraint and the > preferably substituted parameter mapping alongside it. > > gcc/testsuite/ChangeLog: > > * g++.dg/concepts/diagnostic6.C: New test. > --- > gcc/cp/cxx-pretty-print.c | 12 ++++--- > gcc/cp/cxx-pretty-print.h | 1 + > gcc/cp/error.c | 36 +++++++-------------- > gcc/testsuite/g++.dg/concepts/diagnostic6.C | 14 ++++++++ > 4 files changed, 33 insertions(+), 30 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic6.C > > diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c > index 100154e400f..15d8b7eb609 100644 > --- a/gcc/cp/cxx-pretty-print.c > +++ b/gcc/cp/cxx-pretty-print.c > @@ -2878,9 +2878,13 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t) > /* Output the "[with ...]" clause for a parameter mapping of an atomic > constraint. */ > > -static void > +void > pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) > { > + pp_cxx_left_bracket (pp); > + pp->translate_string ("with"); > + pp_cxx_whitespace (pp); > + > for (tree p = map; p; p = TREE_CHAIN (p)) > { > tree parm = TREE_VALUE (p); > @@ -2903,6 +2907,8 @@ pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) > if (TREE_CHAIN (p) != NULL_TREE) > pp_cxx_separate_with (pp, ';'); > } > + > + pp_cxx_right_bracket (pp); > } > > void > @@ -2915,12 +2921,8 @@ pp_cxx_atomic_constraint (cxx_pretty_printer *pp, tree t) > tree map = ATOMIC_CONSTR_MAP (t); > if (map && map != error_mark_node) > { > - pp_cxx_whitespace (pp); > - pp_cxx_left_bracket (pp); > - pp->translate_string ("with"); > pp_cxx_whitespace (pp); Is there a reason not to move the initial whitespace as well, like in dump_substitution? OK with that change. > pp_cxx_parameter_mapping (pp, map); > - pp_cxx_right_bracket (pp); > } > } > > diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h > index 7c7347f57ba..494f3fdde59 100644 > --- a/gcc/cp/cxx-pretty-print.h > +++ b/gcc/cp/cxx-pretty-print.h > @@ -112,5 +112,6 @@ void pp_cxx_conjunction (cxx_pretty_printer *, tree); > void pp_cxx_disjunction (cxx_pretty_printer *, tree); > void pp_cxx_constraint (cxx_pretty_printer *, tree); > void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree); > +void pp_cxx_parameter_mapping (cxx_pretty_printer *, tree); > > #endif /* GCC_CXX_PRETTY_PRINT_H */ > diff --git a/gcc/cp/error.c b/gcc/cp/error.c > index cc51b6ffe13..9f19e9bbaa4 100644 > --- a/gcc/cp/error.c > +++ b/gcc/cp/error.c > @@ -3680,27 +3680,6 @@ print_location (diagnostic_context *context, location_t loc) > "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) > { > @@ -3717,12 +3696,19 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree > 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); > + > + cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer; > + pp_verbatim (pp, "required for the satisfaction of %qE", expr); > + if (map) > + { > + tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); > + pp_cxx_whitespace (pp); > + pp_cxx_parameter_mapping (pp, (subst_map != error_mark_node > + ? subst_map : map)); > + } > + pp_newline (pp); > } > > /* Diagnose the entry point into the satisfaction error. Returns the next > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic6.C b/gcc/testsuite/g++.dg/concepts/diagnostic6.C > new file mode 100644 > index 00000000000..06b17caccbe > --- /dev/null > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic6.C > @@ -0,0 +1,14 @@ > +// { dg-do compile { target c++2a } } > + > +template<typename T> > + concept C = requires (T t) { t + 0; }; > +// { dg-message "satisfaction of .C<T>. .with T = typename T::type." "" { target *-*-* } .-1 } > + > +template<typename T> > + concept D = C<T>; > +// { dg-message "satisfaction of .D<typename T::type>. .with T = int." "" { target *-*-* } .-1 } > + > +template<typename T> > + concept E = D<typename T::type>; > + > +static_assert(E<int>); // { dg-error "static assertion failed|not a class" } >
On Thu, 19 Mar 2020, Jason Merrill wrote: > On 3/19/20 12:50 PM, Patrick Palka wrote: > > On Thu, 19 Mar 2020, Jason Merrill wrote: > > > > > On 3/18/20 3:26 PM, Patrick Palka wrote: > > > > + if (map) > > > > + { > > > > + pp_cxx_whitespace (pp); > > > > + pp_cxx_left_bracket (pp); > > > > + pp->translate_string ("with"); > > > > + pp_cxx_whitespace (pp); > > > > + pp_cxx_parameter_mapping (pp, map); > > > > + pp_cxx_right_bracket (pp); > > > > + } > > > > > > Perhaps we should move the [with ] bits into pp_cxx_parameter_mapping > > > rather > > > than duplicate them here. > > > > Like this? > > > > -- >8 -- > > > > gcc/cp/ChangeLog: > > > > * cxx-pretty-print.c (pp_cxx_parameter_mapping): Make extern. Move > > the "[with ]" bits to here from ... > > (pp_cxx_atomic_constraint): ... here. > > * cxx-pretty-print.h (pp_cxx_parameter_mapping): Declare. > > * error.c (rebuild_concept_check): Delete. > > (print_concept_check_info): Print the dependent form of the constraint > > and the > > preferably substituted parameter mapping alongside it. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/concepts/diagnostic6.C: New test. > > --- > > gcc/cp/cxx-pretty-print.c | 12 ++++--- > > gcc/cp/cxx-pretty-print.h | 1 + > > gcc/cp/error.c | 36 +++++++-------------- > > gcc/testsuite/g++.dg/concepts/diagnostic6.C | 14 ++++++++ > > 4 files changed, 33 insertions(+), 30 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic6.C > > > > diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c > > index 100154e400f..15d8b7eb609 100644 > > --- a/gcc/cp/cxx-pretty-print.c > > +++ b/gcc/cp/cxx-pretty-print.c > > @@ -2878,9 +2878,13 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree > > t) > > /* Output the "[with ...]" clause for a parameter mapping of an atomic > > constraint. */ > > -static void > > +void > > pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) > > { > > + pp_cxx_left_bracket (pp); > > + pp->translate_string ("with"); > > + pp_cxx_whitespace (pp); > > + > > for (tree p = map; p; p = TREE_CHAIN (p)) > > { > > tree parm = TREE_VALUE (p); > > @@ -2903,6 +2907,8 @@ pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree > > map) > > if (TREE_CHAIN (p) != NULL_TREE) > > pp_cxx_separate_with (pp, ';'); > > } > > + > > + pp_cxx_right_bracket (pp); > > } > > void > > @@ -2915,12 +2921,8 @@ pp_cxx_atomic_constraint (cxx_pretty_printer *pp, > > tree t) > > tree map = ATOMIC_CONSTR_MAP (t); > > if (map && map != error_mark_node) > > { > > - pp_cxx_whitespace (pp); > > - pp_cxx_left_bracket (pp); > > - pp->translate_string ("with"); > > pp_cxx_whitespace (pp); > > Is there a reason not to move the initial whitespace as well, like in > dump_substitution? OK with that change. No good reason :) Thanks, patch committed with that change. > > > pp_cxx_parameter_mapping (pp, map); > > - pp_cxx_right_bracket (pp); > > } > > } > > diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h > > index 7c7347f57ba..494f3fdde59 100644 > > --- a/gcc/cp/cxx-pretty-print.h > > +++ b/gcc/cp/cxx-pretty-print.h > > @@ -112,5 +112,6 @@ void pp_cxx_conjunction (cxx_pretty_printer *, tree); > > void pp_cxx_disjunction (cxx_pretty_printer *, tree); > > void pp_cxx_constraint (cxx_pretty_printer *, tree); > > void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree); > > +void pp_cxx_parameter_mapping (cxx_pretty_printer *, tree); > > #endif /* GCC_CXX_PRETTY_PRINT_H */ > > diff --git a/gcc/cp/error.c b/gcc/cp/error.c > > index cc51b6ffe13..9f19e9bbaa4 100644 > > --- a/gcc/cp/error.c > > +++ b/gcc/cp/error.c > > @@ -3680,27 +3680,6 @@ print_location (diagnostic_context *context, > > location_t loc) > > "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) > > { > > @@ -3717,12 +3696,19 @@ print_concept_check_info (diagnostic_context > > *context, tree expr, tree map, tree > > 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); > > + > > + cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer; > > + pp_verbatim (pp, "required for the satisfaction of %qE", expr); > > + if (map) > > + { > > + tree subst_map = tsubst_parameter_mapping (map, args, tf_none, > > NULL_TREE); > > + pp_cxx_whitespace (pp); > > + pp_cxx_parameter_mapping (pp, (subst_map != error_mark_node > > + ? subst_map : map)); > > + } > > + pp_newline (pp); > > } > > /* Diagnose the entry point into the satisfaction error. Returns the > > next > > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic6.C > > b/gcc/testsuite/g++.dg/concepts/diagnostic6.C > > new file mode 100644 > > index 00000000000..06b17caccbe > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic6.C > > @@ -0,0 +1,14 @@ > > +// { dg-do compile { target c++2a } } > > + > > +template<typename T> > > + concept C = requires (T t) { t + 0; }; > > +// { dg-message "satisfaction of .C<T>. .with T = typename T::type." "" { > > target *-*-* } .-1 } > > + > > +template<typename T> > > + concept D = C<T>; > > +// { dg-message "satisfaction of .D<typename T::type>. .with T = int." "" { > > target *-*-* } .-1 } > > + > > +template<typename T> > > + concept E = D<typename T::type>; > > + > > +static_assert(E<int>); // { dg-error "static assertion failed|not a class" > > } > > > >
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 100154e400f..1e89c3f9033 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2878,7 +2878,7 @@ pp_cxx_check_constraint (cxx_pretty_printer *pp, tree t) /* Output the "[with ...]" clause for a parameter mapping of an atomic constraint. */ -static void +void pp_cxx_parameter_mapping (cxx_pretty_printer *pp, tree map) { for (tree p = map; p; p = TREE_CHAIN (p)) diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h index 7c7347f57ba..494f3fdde59 100644 --- a/gcc/cp/cxx-pretty-print.h +++ b/gcc/cp/cxx-pretty-print.h @@ -112,5 +112,6 @@ void pp_cxx_conjunction (cxx_pretty_printer *, tree); void pp_cxx_disjunction (cxx_pretty_printer *, tree); void pp_cxx_constraint (cxx_pretty_printer *, tree); void pp_cxx_constrained_type_spec (cxx_pretty_printer *, tree); +void pp_cxx_parameter_mapping (cxx_pretty_printer *, tree); #endif /* GCC_CXX_PRETTY_PRINT_H */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index cc51b6ffe13..4bf835e84a1 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3680,27 +3680,6 @@ print_location (diagnostic_context *context, location_t loc) "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) { @@ -3717,12 +3696,22 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree 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); + + cxx_pretty_printer *pp = (cxx_pretty_printer *)context->printer; + pp_verbatim (pp, "required for the satisfaction of %qE", expr); + map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); + if (map && map != error_mark_node) + { + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + pp_cxx_parameter_mapping (pp, map); + pp_cxx_right_bracket (pp); + } + pp_newline (pp); } /* Diagnose the entry point into the satisfaction error. Returns the next diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic6.C b/gcc/testsuite/g++.dg/concepts/diagnostic6.C new file mode 100644 index 00000000000..06b17caccbe --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/diagnostic6.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++2a } } + +template<typename T> + concept C = requires (T t) { t + 0; }; +// { dg-message "satisfaction of .C<T>. .with T = typename T::type." "" { target *-*-* } .-1 } + +template<typename T> + concept D = C<T>; +// { dg-message "satisfaction of .D<typename T::type>. .with T = int." "" { target *-*-* } .-1 } + +template<typename T> + concept E = D<typename T::type>; + +static_assert(E<int>); // { dg-error "static assertion failed|not a class" }