diff mbox series

[pushed] c++: pack in enumerator in lambda [PR100198]

Message ID 20220128032128.1399214-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: pack in enumerator in lambda [PR100198] | expand

Commit Message

Jason Merrill Jan. 28, 2022, 3:21 a.m. UTC
The GCC 8 lambda overhaul fixed most uses of lambdas in pack expansions, but
local enums and classes within such lambdas that depend on parameter packs
are still broken.  For now, give a sorry instead of an ICE or incorrect
error.

Tested x86_64-pc-linux-gnu, applying to trunk.

	PR c++/100198
	PR c++/100030
	PR c++/100282

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_enumerator_definition): Sorry on parameter
	pack in lambda.
	(cp_parser_class_head): And in class attributes.
	* pt.cc (check_for_bare_parameter_packs): Sorry instead of error
	in lambda.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/lambda/lambda-variadic13.C: Accept the sorry
	as well as the correct error.
	* g++.dg/cpp0x/lambda/lambda-variadic14.C: Likewise.
	* g++.dg/cpp0x/lambda/lambda-variadic14a.C: New test.
	* g++.dg/cpp0x/lambda/lambda-variadic15.C: New test.
	* g++.dg/cpp0x/lambda/lambda-variadic16.C: New test.
---
 gcc/cp/parser.cc                              | 19 ++++++++++++++-
 gcc/cp/pt.cc                                  | 23 +++++++++++++++----
 .../g++.dg/cpp0x/lambda/lambda-variadic13.C   |  2 +-
 .../g++.dg/cpp0x/lambda/lambda-variadic14.C   |  2 +-
 .../g++.dg/cpp0x/lambda/lambda-variadic14a.C  |  9 ++++++++
 .../g++.dg/cpp0x/lambda/lambda-variadic15.C   | 14 +++++++++++
 .../g++.dg/cpp0x/lambda/lambda-variadic16.C   | 13 +++++++++++
 7 files changed, 75 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14a.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic15.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic16.C


base-commit: 66b86171188dcb61d2d0e0a4a98a7467e58a84a7
diff mbox series

Patch

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f1947ee3a1c..94a5c64be4c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -21146,7 +21146,16 @@  cp_parser_enumerator_definition (cp_parser* parser, tree type)
 
   /* If we are processing a template, make sure the initializer of the
      enumerator doesn't contain any bare template parameter pack.  */
-  if (check_for_bare_parameter_packs (value))
+  if (current_lambda_expr ())
+    {
+      /* In a lambda it should work, but doesn't currently.  */
+      if (uses_parameter_packs (value))
+	{
+	  sorry ("unexpanded parameter pack in enumerator in lambda");
+	  value = error_mark_node;
+	}
+    }
+  else if (check_for_bare_parameter_packs (value))
     value = error_mark_node;
 
   /* Create the enumerator.  */
@@ -26624,6 +26633,14 @@  cp_parser_class_head (cp_parser* parser,
 
   if (type)
     {
+      if (current_lambda_expr ()
+	  && uses_parameter_packs (attributes))
+	{
+	  /* In a lambda this should work, but doesn't currently.  */
+	  sorry ("unexpanded parameter pack in local class in lambda");
+	  attributes = NULL_TREE;
+	}
+
       /* Apply attributes now, before any use of the class as a template
 	 argument in its base list.  */
       cplus_decl_attributes (&type, attributes, (int)ATTR_FLAG_TYPE_IN_PLACE);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 19e73b3b77d..f46a7ad6655 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4273,10 +4273,27 @@  check_for_bare_parameter_packs (tree t, location_t loc /* = UNKNOWN_LOCATION */)
   cp_walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
   delete ppd.visited;
 
+  if (!parameter_packs)
+    return false;
+
+  if (loc == UNKNOWN_LOCATION)
+    loc = cp_expr_loc_or_input_loc (t);
+
   /* It's OK for a lambda to have an unexpanded parameter pack from the
      containing context, but do complain about unexpanded capture packs.  */
-  if (current_class_type && LAMBDA_TYPE_P (current_class_type)
-      && CLASSTYPE_TEMPLATE_INFO (current_class_type))
+  tree lam = current_lambda_expr ();
+  if (lam)
+    lam = TREE_TYPE (lam);
+
+  if (lam && lam != current_class_type)
+    {
+      /* We're in a lambda, but it isn't the innermost class.
+	 This should work, but currently doesn't.  */
+      sorry_at (loc, "unexpanded parameter pack in local class in lambda");
+      return true;
+    }
+
+  if (lam && CLASSTYPE_TEMPLATE_INFO (lam))
     for (; parameter_packs;
 	 parameter_packs = TREE_CHAIN (parameter_packs))
       {
@@ -4287,8 +4304,6 @@  check_for_bare_parameter_packs (tree t, location_t loc /* = UNKNOWN_LOCATION */)
 
   if (parameter_packs)
     {
-      if (loc == UNKNOWN_LOCATION)
-	loc = cp_expr_loc_or_input_loc (t);
       error_at (loc, "parameter packs not expanded with %<...%>:");
       while (parameter_packs)
         {
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic13.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic13.C
index ac4e631ebb5..3df88296726 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic13.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic13.C
@@ -3,7 +3,7 @@ 
 
 template <class... Ts>
 void f() {
-  [] { struct S : Ts { }; };	// { dg-error "not expanded" }
+  [] { struct S : Ts { }; };	// { dg-message "" }
 }
 
 int main() {
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14.C
index 185aa0332e7..4634f16ccb0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14.C
@@ -3,6 +3,6 @@ 
 
 template <int... E>
 void f() {
-  [] { enum e { e = E }; };	// { dg-error "not expanded" }
+  [] { enum e { e = E }; };	// { dg-message "" }
 }
 template void f<>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14a.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14a.C
new file mode 100644
index 00000000000..810b4a4e045
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14a.C
@@ -0,0 +1,9 @@ 
+// PR c++/100198
+// { dg-do compile { target c++11 } }
+
+template <int... E>
+void f() {
+  ([] { enum e { e = E }; }(), ...); // { dg-bogus "" "" { xfail *-*-* } }
+}
+
+template void f<0>();
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic15.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic15.C
new file mode 100644
index 00000000000..730215a7a41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic15.C
@@ -0,0 +1,14 @@ 
+// PR c++/100030
+// { dg-do compile { target c++11 } }
+
+template <class... Ts>
+void sink(Ts...);
+
+template <class... Ts>
+void f(Ts...) {
+  sink([] { struct alignas(Ts) S {}; }...); // { dg-bogus "" "" { xfail *-*-* } }
+}
+
+int main() {
+  f(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic16.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic16.C
new file mode 100644
index 00000000000..8e48e38a345
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic16.C
@@ -0,0 +1,13 @@ 
+// PR c++/100282
+// { dg-do compile { target c++11 } }
+
+template <typename... Ts>
+void
+local_class ()
+{
+  int { []{ struct ZZ : Ts {}; }... }; // { dg-bogus "" "" { xfail *-*-* } }
+}
+
+template // <>
+void
+local_class<int> ();