aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2025-08-13 22:07:27 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2025-08-13 22:10:18 +0200
commit458773ac7bca792db044ad6c241f566c9ba87cb7 (patch)
tree306c5f950a9f2c08c7d04ef0f049ab1688c6f00f /gcc/testsuite
parent5fedaa2347939dcad24581608520067ec6560758 (diff)
downloadgcc-458773ac7bca792db044ad6c241f566c9ba87cb7.zip
gcc-458773ac7bca792db044ad6c241f566c9ba87cb7.tar.gz
gcc-458773ac7bca792db044ad6c241f566c9ba87cb7.tar.bz2
c++: Implement C++26 P1306R5 - Expansion statements [PR120776]
The following patch implements the C++26 P1306R5 - Expansion statements paper. When expansion statements are used outside of templates, the lowering of the statement uses push_tinst_level_loc and instantiates the body multiple times, otherwise when the new TEMPLATE_FOR_STMT statement is being instantiated and !processing_template_decl, it instantiates the body several times with just local_specialization_stack around each iteration but with the original args. Because the lowering of these statements is mostly about instantiation, I've put the lowering code into pt.cc rather than semantics.cc. Only destructuring expansion statements currently use in the patch temporary lifetime extension which matches the proposed resolution of https://cplusplus.github.io/CWG/issues/3043.html I'm not sure what will CWG decide about that if there will be some temporary lifetime extension for enumerating expansion statements and if yes, under what exact rules (e.g. whether it extends all the temporaries across one iteration of the body, or only if a reference is initialized or nothing at all). And for iterating expansion statements, I think I don't understand the P2686R4 rules well yet, I think if the expansion-initializer is used in static constexpr rvalue reference, then it isn't needed, but not sure if it won't be needed if static would be dropped (whether struct S { constexpr S () : s (0) {} constexpr ~S () {} int s; }; struct T { const S &t, &u; }; void foo () { constexpr T t = { S {}, S {} }; use (t.t, t.u); } is ok under P2686R4; though without constexpr before T I see S::~S () being called after use, not at the end of the t declaration, so maybe it is fine also without static). As per https://cplusplus.github.io/CWG/issues/3044.html the patch uses build_int_cst (ptrdiff_type_node, i) to create second operand of begin + i and doesn't lookup overloaded comma operator (note, I'm actually not even creating a lambda there, just using TARGET_EXPRs). I guess my preference would be dropping those 4 static keywords from [stmt.expand] but the patch does use those for now and it won't be possible to change that until the rest of P2686R4 is implemented. As per https://cplusplus.github.io/CWG/issues/3045.html it treats sk_template_for like sk_for for the purpose of redeclaration of vars in the body but doesn't yet reject [[fallthrough]]; in the expansion stmt body (when not nested in another switch). I'm not sure if cp_perform_range_for_lookup used in the patch is exactly what we want for the https://eel.is/c++draft/stmt.expand#3.2 - it does finish_call_expr on the perform_koenig_lookup as well, shouldn't for the decision whether it is iterating or destructing (i.e. tf_none) just call perform_koenig_lookup and check if it found some FUNCTION_DECL/OVERLOAD/TEMPLATE_DECL? cp_decomp_size in the patch has tsubst_flags_t argument and attempts to be SFINAE friendly, even when it isn't needed strictly for this patch. This is with PR96185 __builtin_structured_binding_size implementation in mind (to follow clang). The new TEMPLATE_FOR_STMT statement is expected to be lowered to something that doesn't use the statement at all, I've implemented break/continue discovery in the body, so all I needed was to punt on TEMPLATE_FOR_STMT in potential_constant_expression_1 so that we don't try to constant evaluate it when it is still dependent (and cxx_eval_constant_expression rejects it without any extra code). I think only enumerating and iterating expansion statements can have zero iteration, because for destructuring ones it doesn't use a structured binding pack and so valid structured binding has to have at least one iteration. Though https://cplusplus.github.io/CWG/issues/3048.html could change that, this patch currently rejects it though. 2025-08-13 Jakub Jelinek <jakub@redhat.com> PR c++/120776 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Predefine __cpp_expansion_statements=202506L for C++26. gcc/cp/ * cp-tree.def: Implement C++26 P1306R5 - Expansion statements. (TEMPLATE_FOR_STMT): New tree code. * cp-tree.h (struct saved_scope): Add expansion_stmt. (in_expansion_stmt): Define. (TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY, TEMPLATE_FOR_SCOPE, TEMPLATE_FOR_INIT_STMT): Define. (struct tinst_level): Adjust comment. (cp_decomp_size, finish_expansion_stmt, do_pushlevel, cp_build_range_for_decls, build_range_temp, cp_perform_range_for_lookup, begin_template_for_scope): Declare. (finish_range_for_stmt): Remove declaration. * cp-objcp-common.cc (cp_common_init_ts): Handle TEMPLATE_FOR_STMT. * name-lookup.h (enum scope_kind): Add sk_template_for enumerator. (struct cp_binding_level): Enlarge kind bitfield from 4 to 5 bits. Adjust comment with remaining space bits. * name-lookup.cc (check_local_shadow): Handle sk_template_for like sk_for. (cp_binding_level_descriptor): Add entry for sk_template_for. (begin_scope): Handle sk_template_for. * parser.h (IN_EXPANSION_STMT): Define. * parser.cc (cp_debug_parser): Print IN_EXPANSION_STMT bit. (cp_parser_lambda_expression): Temporarily clear in_expansion_stmt. (cp_parser_statement): Handle RID_TEMPLATE followed by RID_FOR for C++11. (cp_parser_label_for_labeled_statement): Complain about named labels inside of expansion stmt body. (cp_hide_range_decl): New function. (cp_parser_range_for): Use it. Adjust do_range_for_auto_deduction caller. Remove second template argument from auto_vecs bindings and names. (build_range_temp): No longer static. (do_range_for_auto_deduction): Add expansion_stmt argument. (cp_build_range_for_decls): New function. (cp_convert_range_for): Use it. Call cp_perform_range_for_lookup rather than cp_parser_perform_range_for_lookup. (cp_parser_perform_range_for_lookup): Rename to ... (cp_perform_range_for_lookup): ... this. No longer static. Add complain argument and handle it. (cp_parser_range_for_member_function): Rename to ... (cp_range_for_member_function): ... this. (cp_parser_expansion_statement): New function. (cp_parser_jump_statement): Handle IN_EXPANSION_STMT. (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction caller. Call cp_perform_range_for_lookup rather than cp_parser_perform_range_for_lookup. * error.cc (print_instantiation_full_context): Handle tldcl being TEMPLATE_FOR_STMT. (print_instantiation_partial_context_line): Likewise. * constexpr.cc (potential_constant_expression_1): Handle TEMPLATE_FOR_STMT. * decl.cc (poplevel_named_label_1): Use obl instead of bl->level_chain. (finish_case_label): Diagnose case labels inside of template for. (find_decomp_class_base): Add complain argument, don't diagnose anything and just return error_mark_node if tf_none, adjust recursive call. (cp_decomp_size): New function. (cp_finish_decomp): Adjust find_decomp_class_base caller. * semantics.cc (do_pushlevel): No longer static. (begin_template_for_scope): New function. * pt.cc (push_tinst_level_loc): Handle TEMPLATE_FOR_STMT. (reopen_tinst_level): Likewise. (tsubst_stmt): Handle TEMPLATE_FOR_STMT. (struct expansion_stmt_bc): New type. (expansion_stmt_find_bc_r, finish_expansion_stmt): New functions. * decl2.cc (decl_dependent_p): Return true for current function's decl if in_expansion_stmt. * call.cc (extend_ref_init_temps): Don't extend_all_temps if TREE_STATIC (decl). * cxx-pretty-print.cc (cxx_pretty_printer::statement): Handle TEMPLATE_FOR_STMT. gcc/testsuite/ * g++.dg/cpp1z/decomp64.C: New test. * g++.dg/cpp26/expansion-stmt1.C: New test. * g++.dg/cpp26/expansion-stmt2.C: New test. * g++.dg/cpp26/expansion-stmt3.C: New test. * g++.dg/cpp26/expansion-stmt4.C: New test. * g++.dg/cpp26/expansion-stmt5.C: New test. * g++.dg/cpp26/expansion-stmt6.C: New test. * g++.dg/cpp26/expansion-stmt7.C: New test. * g++.dg/cpp26/expansion-stmt8.C: New test. * g++.dg/cpp26/expansion-stmt9.C: New test. * g++.dg/cpp26/expansion-stmt10.C: New test. * g++.dg/cpp26/expansion-stmt11.C: New test. * g++.dg/cpp26/expansion-stmt12.C: New test. * g++.dg/cpp26/expansion-stmt13.C: New test. * g++.dg/cpp26/expansion-stmt14.C: New test. * g++.dg/cpp26/expansion-stmt15.C: New test. * g++.dg/cpp26/expansion-stmt16.C: New test. * g++.dg/cpp26/expansion-stmt17.C: New test. * g++.dg/cpp26/expansion-stmt18.C: New test. * g++.dg/cpp26/expansion-stmt19.C: New test. * g++.dg/cpp26/feat-cxx26.C: Add __cpp_expansion_statements tests.
Diffstat (limited to 'gcc/testsuite')
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/decomp64.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C216
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C93
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C54
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt13.C97
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt14.C75
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C47
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C68
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C58
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C94
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C208
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C197
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C35
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C96
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C88
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt7.C89
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt8.C109
-rw-r--r--gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C110
-rw-r--r--gcc/testsuite/g++.dg/cpp26/feat-cxx26.C6
21 files changed, 1810 insertions, 0 deletions
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp64.C b/gcc/testsuite/g++.dg/cpp1z/decomp64.C
new file mode 100644
index 0000000..e715b9e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp64.C
@@ -0,0 +1,16 @@
+// PR c++/120776
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern int b[];
+
+void
+foo (int n)
+{
+ int a[n];
+ a[0] = 42;
+ auto [x] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ // { dg-error "cannot decompose variable length array 'int \\\[n\\\]'" "" { target *-*-* } .-1 }
+ auto [y] = b; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ // { dg-error "deduced type 'int \\\[\\\]' for '<structured bindings>' is incomplete" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
new file mode 100644
index 0000000..077b70c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
@@ -0,0 +1,216 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto &g : { d, e, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+}
+
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i;
+ static_assert (is_same_v <decltype (i), int>);
+ }
+ return r;
+}
+
+int
+baz ()
+{
+ int a[] = { 2, 4, 6, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == 6)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+long long
+qux ()
+{
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = 0;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+long long
+corge ()
+{
+ long long r = 0;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : O::D {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+int
+freddy ()
+{
+ S a[] = { { 2, 4, 6 }, { 8, 10, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+long long
+quux ()
+{
+ long long r = 0;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i * j * k; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+long long
+boo ()
+{
+ long long r = 0;
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ switch (g)
+ {
+ case 1:
+ r += 3;
+ break;
+ case 2:
+ r += 5;
+ break;
+ case 3:
+ r += 9;
+ break;
+ case 4:
+ r += 13;
+ break;
+ default:
+ __builtin_abort ();
+ }
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+ if (bar () != 15)
+ __builtin_abort ();
+ if (baz () != 34)
+ __builtin_abort ();
+ if (qux () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply () != 297)
+ __builtin_abort ();
+ if (freddy () != 92)
+ __builtin_abort ();
+ if (quux () != 4871)
+ __builtin_abort ();
+ if (boo () != 30)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C
new file mode 100644
index 0000000..dfa286b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt10.C
@@ -0,0 +1,17 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int a;
+long b;
+
+void
+foo ()
+{
+ template for (auto g : { &a, &b, 2L, &a }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message "required from here" "" { target *-*-* } .-1 }
+ decltype (*g) h = *g; // { dg-error "invalid type argument of unary" }
+ }
+}
+
+// { dg-message "In instantiation of 'template for' iteration 3:" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C
new file mode 100644
index 0000000..0156806
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt11.C
@@ -0,0 +1,93 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { using type = S; int s; };
+S a = { 1 }, b = { 2 };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct T { using type = T; int s; };
+T d = { 8 };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+struct V { int a; long b; double c; };
+
+void
+foo ()
+{
+ template for (auto g : { a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g;
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (auto g : { a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g;
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+template <typename S, typename U, typename V>
+void
+baz ()
+{
+ template for (auto g : { (S) a, b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ template for (auto g : { d, (S) b }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ static constexpr U u = { 3 };
+ template for (auto g : u) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+ V v = { 9, 10L, 11.0 };
+ template for (auto g : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ decltype(g)::type h = g; // { dg-error "need 'typename' before 'decltype \\\(g\\\)::type' because 'decltype \\\(g\\\)' is a dependent scope" }
+ }
+}
+
+void
+qux ()
+{
+ bar <0> ();
+ baz <S, U, V> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C
new file mode 100644
index 0000000..3b31e37
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt12.C
@@ -0,0 +1,54 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+constexpr int
+foo (auto const &... x) // { dg-warning "use of 'auto' in parameter declaration only available with" "" { target c++17_down } }
+{
+ int r = 0;
+ template for (auto const &c : {x...}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += c[0];
+ return r;
+}
+
+constexpr int c1[] = { 1, 2, 3 };
+constexpr int c2[] = { 4, 3, 2, 1 };
+static_assert (foo (c1, c2) == 5, "");
+
+template <typename T, unsigned long N>
+struct array
+{
+ T e[N];
+ constexpr T *begin () noexcept { return &e[0]; }
+ constexpr const T *begin () const noexcept { return &e[0]; }
+ constexpr T *end () noexcept { return &e[N]; }
+ constexpr const T *end () const noexcept { return &e[N]; }
+};
+
+static constexpr array <int, 3> a { 1, 2, 3 };
+
+constexpr int
+bar ()
+{
+ int r = 0;
+ template for (constexpr int s : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += sizeof (char[s]);
+ return r;
+}
+
+static_assert (bar () == 6, "");
+
+struct S { int i; short s; };
+
+constexpr long
+baz (S s)
+{
+ long r = 0;
+ template for (auto x : s) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += sizeof (x);
+ }
+ return r;
+}
+
+static_assert (baz (S {}) == sizeof (int) + sizeof (short), "");
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt13.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt13.C
new file mode 100644
index 0000000..087c707
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt13.C
@@ -0,0 +1,97 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct S { int s; };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+
+struct V {
+ int i, j;
+ template <int I> int &get () { return i; }
+};
+
+template<> struct std::tuple_size <V> { static const int value = 2; };
+template<int I> struct std::tuple_element <I, V> { using type = int; };
+
+struct W {
+ int w;
+ W (int x) : w (x) {}
+ ~W () {}
+};
+
+struct X {
+ V i, j;
+ template <int I> V &get () { return j; }
+};
+
+template<> struct std::tuple_size <X> { static const int value = 3; };
+template<int I> struct std::tuple_element <I, X> { using type = V; };
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto h = 2; constexpr auto g : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g.s + h;
+ template for (long long h = ++r; auto g : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ __builtin_abort ();
+ return r;
+}
+
+long long
+bar ()
+{
+ long long r = 0;
+ template for (W w { 42 }; auto i : V { 42, 10 }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i + (w.w == 42);
+ return r;
+}
+
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; auto [ i, j ] : X { { 5, 6 }, { 7, 8 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i + j + (x == 5); // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+V &&
+qux (V &&x) noexcept
+{
+ return static_cast<V &&> (x);
+}
+
+long long
+freddy ()
+{
+ long long r = 0;
+ V a { 1, 2 }, b { 3, 4 };
+ template for (auto i : { qux (static_cast<V &&> (a)), qux (static_cast<V &&> (b)) }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i.i + i.j;
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 19)
+ __builtin_abort ();
+ if (bar () != 86)
+ __builtin_abort ();
+ if (baz () != 45)
+ __builtin_abort ();
+ if (freddy () != 10)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt14.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt14.C
new file mode 100644
index 0000000..ffdbe07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt14.C
@@ -0,0 +1,75 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+struct S { int s; };
+constexpr S c[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct U {
+ constexpr const S *begin () const { return &c[0]; }
+ constexpr const S *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+struct V {
+ constexpr V () : a (1), b (2), c (3.0) {}
+ constexpr int foo () const { return a; }
+ constexpr unsigned long bar () const { return b; }
+ constexpr double baz () const { return c; }
+ int a;
+ unsigned long b;
+ double c;
+};
+
+long long
+foo ()
+{
+ long long r = 0;
+ template for (constexpr auto h = 2; constexpr auto g : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto i = g.s + h;
+ r += i;
+ }
+ template for (constexpr auto h = 42; constexpr auto g : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto i = g.s + h;
+ __builtin_abort ();
+ }
+ return r;
+}
+
+long long
+bar ()
+{
+ long long r = 0;
+ template for (constexpr S a { 42 }; constexpr auto b : { S { 1 }, S { 3 }, S { 5 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto c = a.s + b.s;
+ r += c;
+ }
+ return r;
+}
+
+constexpr V v;
+
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; constexpr auto y : v) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ constexpr auto z = x + y;
+ r += z;
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo () != 18)
+ __builtin_abort ();
+ if (bar () != 135)
+ __builtin_abort ();
+ if (baz () != 21)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
new file mode 100644
index 0000000..8f8ed75
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C
@@ -0,0 +1,47 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T>
+ struct initializer_list {
+ private:
+ T *a;
+ decltype (sizeof 0) b;
+ public:
+ constexpr decltype (sizeof 0) size () const noexcept { return b; }
+ constexpr const T *begin () const noexcept { return a; }
+ constexpr const T *end () const noexcept { return begin () + size (); }
+};
+}
+
+struct A {};
+struct B { int b; B () : b (42) {} };
+struct C : public B { int c; C () : c (42), B () {} };
+extern int f[];
+
+void
+foo (int n)
+{
+ int c[0] = {}, d[n];
+ int e = 42;
+ d[0] = 42;
+ template for (auto a : A {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose class type 'A' without non-static data members" "" { target *-*-* } .-1 }
+ template for (int b : B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ;
+ template for (int i : c) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "empty structured binding" "" { target *-*-* } .-1 }
+ template for (int i : d) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose variable length array" "" { target *-*-* } .-1 }
+ template for (auto a : C {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose class type 'C': both it and its base class 'B' have non-static data members" "" { target *-*-* } .-1 }
+ template for (auto a : e) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose non-array non-class type 'int'" "" { target *-*-* } .-1 }
+ template for (auto a : { .id1 = 5, .id2 = 6LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "designators in 'template for' initializer" "" { target *-*-* } .-1 }
+ template for (auto a : { .id3 { 5 }, .id4 = { 1.0 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "designators in 'template for' initializer" "" { target *-*-* } .-1 }
+ template for (int i : f) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "cannot decompose array of unknown bound 'int \\\[\\\]'" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C
new file mode 100644
index 0000000..e6f914e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt16.C
@@ -0,0 +1,68 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A { int s; };
+constexpr A a[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct B {
+ constexpr const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+constexpr B b = { 3 };
+struct C {
+ C (int x) : s (x) {}
+ constexpr const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+struct D {
+ constexpr D (int x) : s (x) {}
+ constexpr const A *begin () const { return &a[0]; }
+ const A *end () const { return &a[s]; }
+ int s;
+};
+struct E {
+ constexpr E (int x) : s (x) {}
+ const A *begin () const { return &a[0]; }
+ constexpr const A *end () const { return &a[s]; }
+ int s;
+};
+struct F { F () : s (42) {} F (int x) : s (x) {} int s; };
+F g[] = { { 3 }, { 4 }, { 5 }, { 6 }, { 7 } };
+struct G {
+ constexpr G (int x) : s (x) {}
+ constexpr F *begin () const { return &g[0]; }
+ constexpr F *end () const { return &g[s]; }
+ int s;
+};
+struct H { int a; F b; int c; };
+
+void
+foo ()
+{
+ B c = { 3 };
+ template for (constexpr auto g : c) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'c' is not a constant expression" "" { target *-*-* } .-1 }
+ C d = { 3 };
+ template for (constexpr auto g : d) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'d' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* C::begin\\\(\\\) const'" "" { target c++11_down } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* C::end\\\(\\\) const'" "" { target c++11_down } .-2 }
+ constexpr D e = { 3 };
+ template for (constexpr auto g : e) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'e' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* D::end\\\(\\\) const'" "" { target *-*-* } .-1 }
+ constexpr E f = { 3 };
+ template for (constexpr auto g : f) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'f' is not a constant expression" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'const A\\\* E::begin\\\(\\\) const'" "" { target *-*-* } .-1 }
+ constexpr G h = { 3 };
+ template for (constexpr auto g : h) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "'h' is not a constant expression" "" { target *-*-* } .-1 }
+ template for (constexpr auto g : { 1, 2, F { 3 }, 4L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target *-*-* } .-1 }
+ template for (constexpr auto g : H {})// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target *-*-* } .-1 }
+ // { dg-error "call to non-'constexpr' function 'F::F\\\(\\\)'" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C
new file mode 100644
index 0000000..1d4e310
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt17.C
@@ -0,0 +1,37 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+// { dg-additional-options "-frange-for-ext-temps" { target c++20_down } }
+
+int c;
+struct A {
+ A () { ++c; }
+ ~A () { --c; }
+ A (int x) : a (x) { ++c; }
+ A (const A &x) : a (x.a) { ++c; }
+ int a;
+};
+struct B { int a; long b; double c; short d; };
+
+B &
+foo (A x, A y, A z)
+{
+ static B r = { 1, 2, 42, 3 };
+ return r;
+}
+
+int
+main ()
+{
+ int r = 0;
+ if (c != 0)
+ __builtin_abort ();
+ template for (auto a : foo (A { 1 }, A { 2 }, A { 42 })) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (c != 3)
+ __builtin_abort ();
+ r += a;
+ }
+ if (c != 0 || r != 48)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
new file mode 100644
index 0000000..a3e7dd76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
@@ -0,0 +1,58 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+struct S { int a; long b; short c; };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+void
+foo ()
+{
+ template for (int a = 1; auto a : { 1, 2L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto a'" "" { target *-*-* } .-1 }
+ template for (int b = 1; auto c : { 1, 2L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ;
+ int b = 1;
+ int c = 2;
+ template for (int d = 1; auto d : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto d'" "" { target *-*-* } .-1 }
+ template for (int e = 1; auto e : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto e'" "" { target *-*-* } .-1 }
+ template for (int f = 1; auto f : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ ; // { dg-error "conflicting declaration 'auto f'" "" { target *-*-* } .-1 }
+ template for (auto g : { 1, 2LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int g = 5; // { dg-error "conflicting declaration 'int g'" }
+ // { dg-error "redeclaration of 'int g'" "" { target *-*-* } .-1 }
+ template for (auto h : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int h = 6; // { dg-error "redeclaration of 'int h'" }
+ template for (auto i : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ int i = 7; // { dg-error "conflicting declaration 'int i'" }
+ // { dg-error "redeclaration of 'int i'" "" { target *-*-* } .-1 }
+ template for (auto j : { 1, 2LL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int j = 5; // { dg-error "conflicting declaration 'int j'" }
+ } // { dg-error "redeclaration of 'int j'" "" { target *-*-* } .-1 }
+ template for (auto k : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int k = 6; // { dg-error "redeclaration of 'int k'" }
+ }
+ template for (auto l : S { 1, 2, 3}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ int l = 7; // { dg-error "conflicting declaration 'int l'" }
+ } // { dg-error "redeclaration of 'int l'" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C
new file mode 100644
index 0000000..59983d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt19.C
@@ -0,0 +1,94 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct V {
+ int i, j;
+ template <int I> int &get () { return i; }
+};
+
+template<> struct std::tuple_size <V> { static const int value = 5; };
+template<int I> struct std::tuple_element <I, V> { using type = int; };
+
+constexpr V c[] = { { 3, 4 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 } };
+struct U {
+ constexpr const V *begin () const { return &c[0]; }
+ constexpr const V *end () const { return &c[s]; }
+ int s;
+};
+constexpr U u1 = { 3 }, u2 = { 0 };
+
+struct W {
+ int w;
+ W (int x) : w (x) {}
+ ~W () {}
+};
+
+struct X {
+ V i, j;
+ template <int I> V &get () { return j; }
+};
+
+template<> struct std::tuple_size <X> { static const int value = 3; };
+template<int I> struct std::tuple_element <I, X> { using type = V; };
+
+template <int N>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto h = 2; auto [_, ...i, _] : u1) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (i) != 3) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort (); // { dg-warning "name-independent declarations only available with" "" { target c++23_down } .-3 }
+ r += i...[1] + h; // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ template for (long long h = ++r; auto [...i, j] : u2) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ __builtin_abort (); // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ return r;
+}
+
+template <int N>
+long long
+bar ()
+{
+ long long r = 0;
+ template for (W w { 42 }; auto [...i, j] : { V { 42, 10 }, V { 15, 26 }, V { 93, 12 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (i) != 4) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort ();
+ r += i...[3] + (w.w == 42); // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ return r;
+}
+
+template <int N>
+long long
+baz ()
+{
+ long long r = 0;
+ template for (constexpr auto x = 5; auto [ ...j ] : X { { 5, 6 }, { 7, 8 } }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (sizeof... (j) != 5) // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 }
+ __builtin_abort ();
+ r += j...[4] + j...[0] + (x == 5); // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+ }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo <0> () != 19)
+ __builtin_abort ();
+ if (bar <1> () != 153)
+ __builtin_abort ();
+ if (baz <2> () != 45)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
new file mode 100644
index 0000000..590638e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
@@ -0,0 +1,208 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++17 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+#if __cpp_nontype_template_parameter_class >= 201806L
+template <auto ... Z>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (const auto &g : { Z... }) // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+}
+#endif
+
+template <typename T, int N>
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : T {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i + N;
+ static_assert (is_same_v <decltype (i), int>);
+ }
+ return r;
+}
+
+template <typename T>
+int
+baz ()
+{
+ T a[] = { 2, 4, 6, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == 6)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <typename T>
+long long
+qux ()
+{
+ T l = { d, e, f, j, k };
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = 0;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+template <typename T>
+long long
+corge ()
+{
+ long long r = 0;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, (T) m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+template <typename T>
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : T {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i;
+ return r;
+}
+
+template <typename T>
+int
+freddy ()
+{
+ T a[] = { { 2, 4, 6 }, { 8, 10, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <typename T, typename U, int N>
+long long
+quux ()
+{
+ T l = { d, e, f, j, k };
+ long long r = 0;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ U u = -1;
+ r += i * j * k + u + N;
+ }
+ return r;
+}
+
+int
+main ()
+{
+#if __cpp_nontype_template_parameter_class >= 201806L
+ if (foo <d, e, f, j, U { 13.0f, 14.5, 15.5 }> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+#endif
+ if (bar <N::B, 0> () != 15)
+ __builtin_abort ();
+ if (bar <N::B, 1> () != 21)
+ __builtin_abort ();
+ if (baz <int> () != 34)
+ __builtin_abort ();
+ if (qux <V> () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge <U> () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply <O::D> () != 297)
+ __builtin_abort ();
+ if (freddy <S> () != 92)
+ __builtin_abort ();
+ if (quux <V, unsigned char, 1> () != 4876L + 5L * (unsigned char) -1)
+ __builtin_abort ();
+ if (quux <V, int, 3> () != 4881)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C
new file mode 100644
index 0000000..b4b16bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C
@@ -0,0 +1,197 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+struct V { S l, m, n; T o; U p; };
+constexpr S d = { 1, 2, 3 }, e = { 4, 5, 6 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+U k = { 13.0f, 14.5, 15.5 }, m = { 7.0f, 7.0, 7.0 };
+V l = { d, e, f, j, k };
+struct A
+{
+ int x;
+ constexpr explicit A (int v) : x(v) {}
+ constexpr A &operator ++ () { ++x; return *this; }
+ constexpr int operator * () { return x; }
+ constexpr bool operator != (const A &o) { return x != o.x; }
+ constexpr A operator + (int o) { A r (x + o); return r; }
+};
+struct C
+{
+ int x, y, z;
+ constexpr explicit C (int u, int v, int w) : x(u), y(v), z(w) {}
+ constexpr C &operator ++ () { ++x; --y; ++z; return *this; }
+ constexpr C operator * () { return *this; }
+ constexpr bool operator != (const C &o) { return x != o.x || y != o.y || z != o.z; }
+ constexpr C operator + (int o) { C r (x + o, y - o, z + o); return r; }
+};
+
+namespace N
+{
+ struct B { constexpr B () {} };
+ constexpr A begin (B &) { return A (0); }
+ constexpr A end (B &) { return A (6); }
+}
+
+namespace O
+{
+ struct D { constexpr D () {} };
+ constexpr C begin (D &) { return C (0, 42, 5); }
+ constexpr C end (D &) { return C (6, 36, 11); }
+}
+
+template <int N>
+long long
+foo ()
+{
+ long long r = 0;
+ template for (auto &g : { d, e, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s) + N;
+ }
+ return r;
+}
+
+template <typename T>
+int
+bar ()
+{
+ int r = 0;
+ template for (auto i : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i;
+ static_assert (is_same_v <decltype (i), T>);
+ }
+ return r;
+}
+
+template <int N>
+int
+baz ()
+{
+ int a[] = { 2, 4, N, 8, 10 };
+ int r = 0, i = 0;
+ template for (const int &w : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ if (&w != &a[i++])
+ break;
+ r += w;
+ if (w == N)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <int N>
+long long
+qux ()
+{
+ long long r = 0;
+ template for (const auto &i : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += i.a * i.b * i.c;
+ decltype (i.a) s = N;
+ decltype (i.c) t = 0;
+ r += sizeof (s) + sizeof (t);
+ }
+ return r;
+}
+
+template <long long N>
+long long
+corge ()
+{
+ long long r = N;
+ int z = 0;
+ template for (const auto &[g, h, i] : { d, e, f, j, m, k, k })// { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ ++z;
+ if (z == 5)
+ continue;
+ ++r;
+ if (z == 7)
+ break;
+ r += g + h + i;
+ decltype (h) s = 0;
+ r += sizeof (s) + sizeof (i);
+ }
+ return r;
+}
+
+template <typename T>
+int
+garply ()
+{
+ int r = 0;
+ template for (auto [g, h, i] : O::D {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += g + h + i + (T) 0; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+template <int N>
+int
+freddy ()
+{
+ S a[] = { { 2, 4, 6 }, { 8, N, 12 }, { 14, 16, 18 } };
+ int r = 0, i = 0;
+ template for (const auto &[u, v, w] : a) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ if (&u != &a[i].a || &v != &a[i].b || &w != &a[i].c)
+ break;
+ ++i;
+ r += u + v + w;
+ if (w == 12)
+ continue;
+ ++r;
+ }
+ return r;
+}
+
+template <long long N>
+long long
+quux ()
+{
+ long long r = N;
+ template for (auto [i, j, k] : l) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += i * j * k; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ return r;
+}
+
+int
+main ()
+{
+ if (foo <0> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+ if (foo <42> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U) + 5 * 42)
+ __builtin_abort ();
+ if (bar <int> () != 15)
+ __builtin_abort ();
+ if (baz <6> () != 34)
+ __builtin_abort ();
+ if (qux <0> () != (4871 + 3 * (sizeof (int) + sizeof (short))
+ + sizeof (long long) + sizeof (signed char)
+ + sizeof (float) + sizeof (long double)))
+ __builtin_abort ();
+ if (corge <0> () != (127 + 3 * (sizeof (long) + sizeof (short))
+ + sizeof (unsigned) + sizeof (signed char)
+ + sizeof (double) + sizeof (long double)))
+ __builtin_abort ();
+ if (garply <long long> () != 297)
+ __builtin_abort ();
+ if (freddy <10> () != 92)
+ __builtin_abort ();
+ if (quux <0> () != 4871)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C
new file mode 100644
index 0000000..8fa9252
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt4.C
@@ -0,0 +1,35 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++14 } }
+// { dg-options "" }
+
+struct S { int a; long b; short c; };
+struct T { long long a; unsigned b; signed char c; };
+struct U { float a; double b; long double c; };
+constexpr S d = { 1, 2, 3 }, f = { 7, 8, 9 };
+constexpr T j = { 10, 11, 12 };
+constexpr U k = { 13.0f, 14.5, 15.5 };
+
+template <typename T>
+long long
+foo ()
+{
+ auto s = [] (auto f)
+ {
+ long long r = 0;
+ template for (auto g : { d, T { 4, 5, 6 }, f, j, k }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ r += g.a + g.b + g.c;
+ decltype (g) s = g;
+ r += sizeof (s);
+ }
+ return r;
+ };
+ return s (f);
+}
+
+int
+main ()
+{
+ if (foo <S> () != 121 + 3 * sizeof (S) + sizeof (T) + sizeof (U))
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C
new file mode 100644
index 0000000..0288cf5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt5.C
@@ -0,0 +1,96 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+void
+foo (int x)
+{
+ switch (x)
+ {
+ case 1:
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : { 1, 2U, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab1:; // { dg-error "identifier label 'lab1' in 'template for' body" }
+ }
+ switch (x)
+ {
+ case 1:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab2:; // { dg-error "identifier label 'lab2' in 'template for' body" }
+ }
+}
+
+template <typename T, T N>
+void
+bar (int x)
+{
+ switch (x)
+ {
+ case 1:
+ template for (auto g : { 1, N, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : { 1, N, 3LL, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : { 1, 2U, N, 4ULL }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab1:; // { dg-error "identifier label 'lab1' in 'template for' body" }
+ }
+ switch (x)
+ {
+ case 1:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ case 2: // { dg-error "jump to case label" }
+ break;
+ }
+ case 3:
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ { // { dg-message " enters 'template for' statement" "" { target *-*-* } .-1 }
+ default: // { dg-error "jump to case label" }
+ break;
+ }
+ }
+ template for (auto g : {}) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ {
+ lab2:; // { dg-error "identifier label 'lab2' in 'template for' body" }
+ }
+}
+
+void
+baz (int x)
+{
+ bar <unsigned, 2U> (x);
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C
new file mode 100644
index 0000000..f6c4771
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt6.C
@@ -0,0 +1,88 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+
+int z[3];
+
+void
+foo ()
+{
+ template for (static auto a : {}) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : {}) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : {}) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : {}) // { dg-error "for-range-declaration cannot be 'register'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : {}) // { dg-error "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : {}) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : {}) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : {}) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : {}) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (enum E { E0 } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+}
+
+void
+bar ()
+{
+ template for (static auto a : z) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : z) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : z) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : z) // { dg-error "for-range-declaration cannot be 'register'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : z) // { dg-error "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : z) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : z) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : z) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : z) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-error "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-2 }
+ template for (enum E { E0 } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt7.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt7.C
new file mode 100644
index 0000000..583521c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt7.C
@@ -0,0 +1,89 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int z[3];
+
+void
+foo ()
+{
+ template for (static auto a : {}) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : {}) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : {}) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : {}) // { dg-warning "for-range-declaration cannot be 'register'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : {}) // { dg-warning "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : {}) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : {}) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : {}) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : {}) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (enum E { E0 } a : {}) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+}
+
+void
+bar ()
+{
+ template for (static auto a : z) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (thread_local auto a : z) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (__thread auto a : z) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'a' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (register auto a : z) // { dg-warning "for-range-declaration cannot be 'register'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (extern auto a : z) // { dg-warning "for-range-declaration cannot be 'extern'" }
+ ; // { dg-error "'a' has both 'extern' and initializer" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto a : z) // { dg-error "non-member 'a' cannot be declared 'mutable'" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (virtual auto a : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (explicit auto a : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (friend auto a : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (typedef auto a : z) // { dg-error "typedef declared 'auto'" }
+ ; // { dg-error "typedef 'a' is initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto a : z) // { dg-error "a variable cannot be declared 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto a : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto a : z) // { dg-error "'inline' specifier invalid for variable 'a' declared at block scope" }
+ ; // { dg-warning "'template for' only available with" "" { target c++23_down } .-1 }
+ template for (struct S { int a; } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "conversion from 'int' to non-scalar type 'bar\\\(\\\)::S' requested" "" { target *-*-* } .-2 }
+ template for (enum E { E0 } a : z) // { dg-error "types may not be defined in a for-range-declaration" }
+ ; // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ // { dg-error "invalid conversion from 'int' to 'bar\\\(\\\)::E'" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt8.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt8.C
new file mode 100644
index 0000000..3d9e91d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt8.C
@@ -0,0 +1,109 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+
+struct S { int y; } z[3];
+
+template <int N>
+void
+foo ()
+{
+ template for (static auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : {}) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (static auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'static'" }
+ ; // { dg-error "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-error "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : z) // { dg-error "for-range-declaration cannot be '__thread'" }
+ ; // { dg-error "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-error "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-error "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-error "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+void
+baz ()
+{
+ foo <0> ();
+ bar <0> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C
new file mode 100644
index 0000000..c2d0cd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt9.C
@@ -0,0 +1,110 @@
+// C++26 P1306R5 - Expansion statements
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { int y; } z[3];
+
+template <int N>
+void
+foo ()
+{
+ template for (static auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : {}) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : {}) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : {}) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : {}) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : {}) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : {}) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+template <int N>
+void
+bar ()
+{
+ template for (static auto [ a ] : z) // { dg-warning "for-range-declaration cannot be 'static'" }
+ ; // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (thread_local auto [ a ] : z) // { dg-warning "for-range-declaration cannot be 'thread_local'" }
+ ; // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-3 }
+ template for (__thread auto [ a ] : z) // { dg-warning "for-range-declaration cannot be '__thread'" }
+ ; // { dg-warning "function-scope 'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+ // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+ // { dg-warning "structured bindings only available with" "" { target c++14_down } .-3 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-4 }
+ template for (register auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'register'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (extern auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'extern'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (mutable auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'mutable'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (virtual auto [ a ] : z) // { dg-error "'virtual' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (explicit auto [ a ] : z) // { dg-error "'explicit' outside class declaration" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (friend auto [ a ] : z) // { dg-error "'friend' used outside of class" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+ template for (typedef auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'typedef'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+#if __cplusplus >= 202002L
+ template for (consteval auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'consteval'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+ template for (constinit auto [ a ] : z) // { dg-error "for-range-declaration cannot be 'constinit'" "" { target c++20 } }
+ ; // { dg-warning "'template for' only available with" "" { target { c++20 && c++23_down } } .-1 }
+#endif
+ template for (inline auto [ a ] : z) // { dg-error "structured binding declaration cannot be 'inline'" }
+ ; // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+ // { dg-warning "'template for' only available with" "" { target c++23_down } .-2 }
+}
+
+void
+baz ()
+{
+ foo <0> ();
+ bar <0> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
index 9284bc2..4fe0680 100644
--- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
+++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
@@ -652,3 +652,9 @@
#elif __cpp_trivial_relocatability != 202502
# error "__cpp_trivial_relocatability != 202502"
#endif
+
+#ifndef __cpp_expansion_statements
+# error "__cpp_expansion_statements"
+#elif __cpp_expansion_statements != 202506
+# error "__cpp_expansion_statements != 202506"
+#endif