c++: Parameter pack in requires parameter list [PR94808]
authorPatrick Palka <ppalka@redhat.com>
Wed, 29 Apr 2020 01:45:54 +0000 (21:45 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 29 Apr 2020 01:45:54 +0000 (21:45 -0400)
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 substitution issue in the
PR altogether.

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 dg-message.

gcc/cp/ChangeLog
gcc/cp/error.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/concepts/diagnostic12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/concepts/diagnostic5.C

index 8728389be831cf669c9621939e0017deecd3c210..c0558015eb8359ec67a25d1f671dfeef7ca989c3 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-29  Patrick Palka  <ppalka@redhat.com>
+
+       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.
+
 2020-04-28  Jason Merrill  <jason@redhat.com>
 
        PR c++/94583
index 98c163db5723474fbc3c10242afb4c83fd5cea30..46970f9b69914e62337aab685b1b7e77888ed1f7 100644 (file)
@@ -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");
 }
index d20308b376c4a5c6202c00ce87489521909c4e29..a824ba8424ea14ef272c021bcc817f3defd31def 100644 (file)
@@ -1,3 +1,9 @@
+2020-04-29  Patrick Palka  <ppalka@redhat.com>
+
+       PR c++/94808
+       * g++.dg/concepts/diagnostic12.C: New test.
+       * g++.dg/concepts/diagnostic5.C: Adjust dg-message.
+
 2020-04-28  Alexandre Oliva <oliva@adacore.com>
 
        PR target/94812
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic12.C b/gcc/testsuite/g++.dg/concepts/diagnostic12.C
new file mode 100644 (file)
index 0000000..a757342
--- /dev/null
@@ -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 }
+
+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" }
index 0d890d6f5489b432f5a89c3e6611a1d5b89fea64..81705f6a0c6d3891983ac91e63d4c4e8d2bbea3f 100644 (file)
@@ -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" }