aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-01-27 17:46:43 -0500
committerJason Merrill <jason@redhat.com>2022-01-27 22:21:43 -0500
commit4d2efec9f229c2e2e7cb6c3f06beb4c3e9d244a1 (patch)
tree96e5220e2ebd90102251f7e3752d3b9326f791a1
parent99f17e996f21d0ed64c36ed1e52977b705143522 (diff)
downloadgcc-4d2efec9f229c2e2e7cb6c3f06beb4c3e9d244a1.zip
gcc-4d2efec9f229c2e2e7cb6c3f06beb4c3e9d244a1.tar.gz
gcc-4d2efec9f229c2e2e7cb6c3f06beb4c3e9d244a1.tar.bz2
c++: pack in enumerator in lambda [PR100198]
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. 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.
-rw-r--r--gcc/cp/parser.cc19
-rw-r--r--gcc/cp/pt.cc23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic13.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic14a.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic15.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic16.C13
7 files changed, 75 insertions, 7 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f1947ee..94a5c64 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 19e73b3..f46a7ad 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 ac4e631..3df8829 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 185aa03..4634f16 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 0000000..810b4a4
--- /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 0000000..730215a
--- /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 0000000..8e48e38
--- /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> ();