On 4/28/20 3:19 PM, Patrick Palka wrote:
On Tue, 28 Apr 2020, Patrick Palka wrote:

On Tue, 28 Apr 2020, Jason Merrill wrote:

On 4/28/20 1:41 PM, Patrick Palka wrote:
On Tue, 28 Apr 2020, Patrick Palka wrote:

On Tue, 28 Apr 2020, Jason Merrill wrote:
On 4/28/20 9:48 AM, Patrick Palka wrote:
When printing the substituted parameter list of a requires-expression
as
part of the "in requirements with ..." context line during concepts
diagnostics, we weren't considering that substitution into a parameter
pack can yield zero or multiple parameters.

Since this patch affects only concepts diagnostics, so far I tested
with
RUNTESTFLAGS="dg.exp=*concepts*" and also verified that we no longer
ICE
with the unreduced testcase in the PR.  Is this OK to commit after a
full bootstrap and regtest?

OK.

Thanks for the review.


Though I wonder about printing the dependent form and template arguments
instead.  Do you have an opinion?

I was going to say that on the one hand, it's convenient to have the
substituted form printed since it would let us to see through
complicated dependent type aliases, but it seems we don't strip type
aliases when pretty printing a parameter and its type with '%q#D'
anyway.  And I can't think of any other possible advantage of printing
the substituted form.

So IMHO printing the dependent form and template arguments instead would
be better here.  I'll try to write a patch for this today.

Like so, tested so far with RUNTESTFLAGS="dg.exp=*concepts*" and also
verified we no longer ICE with the unreduced testcase in the PR.  Does
the following look OK to commit after a full bootstrap and regtest?

-- >8 --

Subject: [PATCH] c++: Parameter pack in requires parameter list [PR94808]

When printing the substituted parameter list of a requires-expression as
part of the "in requirements with ..." context line during concepts
diagnostics, we weren't considering that substitution into a parameter
pack can yield zero or multiple parameters.

This patch changes the way we print the parameter list of a
requires-expression in print_requires_expression_info.  We now print the
dependent form of the parameter list (along with its template parameter
mapping) instead of printing its substituted form.  Besides being an
improvement in its own, this also sidesteps the above parameter pack
expansion issue altogether.

Tested with RUNTESTFLAGS="dg.exp=*concepts*" and also verified we longer
ICE with the unreduced testcase in the PR.  Does this look OK to commit
after a bootstrap and regtest?

gcc/cp/ChangeLog:

        PR c++/94808
        * error.c (print_requires_expression_info): Print the dependent
        form of the parameter list with its template parameter mapping,
        rather than printing the substituted form.

gcc/testsuite/ChangeLog:

        PR c++/94808
        * g++.dg/concepts/diagnostic12.C: New test.
        * g++.dg/concepts/diagnostic5.C: Adjust expected diagnostic.
---
   gcc/cp/error.c                               | 16 ++++------------
   gcc/testsuite/g++.dg/concepts/diagnostic12.C | 16 ++++++++++++++++
   gcc/testsuite/g++.dg/concepts/diagnostic5.C  |  4 ++--
   3 files changed, 22 insertions(+), 14 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic12.C

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 98c163db572..46970f9b699 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3746,7 +3746,6 @@ print_requires_expression_info (diagnostic_context
*context, tree constr, tree a
     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 ");
@@ -3756,19 +3755,12 @@ print_requires_expression_info (diagnostic_context
*context, tree constr, tree a
       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_verbatim (context->printer, "%q#D", parms);
+      if (TREE_CHAIN (parms))
           pp_separate_with_comma ((cxx_pretty_printer *)context->printer);
-
-      parms = next;
+      parms = TREE_CHAIN (parms);
       }
+  pp_cxx_parameter_mapping ((cxx_pretty_printer *)context->printer, map);
       pp_verbatim (context->printer, "\n");
   }
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic12.C
b/gcc/testsuite/g++.dg/concepts/diagnostic12.C
new file mode 100644
index 00000000000..a757342f754
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic12.C
@@ -0,0 +1,16 @@
+// PR c++/94808
+// { dg-do compile { target concepts } }
+
+template<typename T, typename... Args>
+  concept c1 = requires (T t, Args... args) { *t; };
+// { dg-message "in requirements with .T t., .Args ... args. .with.* Args =
\{\}" "" { target *-*-* } .-1 }

Doesn't this print a binding for T?

Yes, but the order in which the binding for T and the binding for Args
is printed appears to be nondeterministic, so I lazily opted to check
for just one of the bindings.

This nondeterminism stems from how find_template_parameters is
implemented, which uses a hash_set<tree> to keep track of seen template
parameters and then builds a TREE_LIST of mappings according to the
(nondeterministic) order of entries in the table.  I think it is
harmless semantically but it does affect diagnostics such as these.

I've just created PR94830 for this issue.

Thanks. I'd think we should build up the list in find_template_parameter_info and only use the hash_set to avoid adding the same parameter more than once.

This patch is OK.



+
+static_assert(c1<int>); // { dg-error "failed" }
+
+void f(...);
+
+template<typename... Args>
+  concept c2 = requires (Args... args) { f(*args...); };
+// { dg-message "in requirements with .Args ... args. .with Args = \{int,
char\}" "" { target *-*-* } .-1 }
+
+static_assert(c2<int, char>); // { dg-error "failed" }
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic5.C
b/gcc/testsuite/g++.dg/concepts/diagnostic5.C
index 0d890d6f548..81705f6a0c6 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic5.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic5.C
@@ -9,7 +9,7 @@ template<typename T>
   template<typename T>
     concept c2 = requires (T x) { *x; };
   // { dg-message "satisfaction of .c2<T>. .with T = char." "" { target
*-*-* } .-1 }
-// { dg-message "in requirements with .char x." "" { target *-*-* } .-2 }
+// { dg-message "in requirements with .T x. .with T = char." "" { target
*-*-* } .-2 }
   // { dg-message "required expression .* is invalid" "" { target *-*-* }
.-3 }
     template<typename T>
@@ -25,7 +25,7 @@ template<typename T>
   template<typename T>
     concept c5 = requires (T x) { { &x } -> c1; };
   // { dg-message "satisfaction of .c5<T>. .with T = char." "" { target
*-*-* } .-1 }
-// { dg-message "in requirements with .char x." "" { target *-*-* } .-2 }
+// { dg-message "in requirements with .T x. .with T = char." "" { target
*-*-* } .-2 }
     template<typename T>
     requires (c1<T> || c2<T>) || (c3<T> || c4<T>) || c5<T> // { dg-message
"49: no operand" }






Reply via email to