2025-06-19 Jakub Jelinek <ja...@redhat.com>
PR c++/117784
* decl.cc: Implement part of C++26 P2686R4 - constexpr structured
bindings.
(cp_finish_decl): Pedwarn for C++23 and older on constinit on
structured bindings except for static/thread_local where it uses
earlier error.
(grokdeclarator): Pedwarn on constexpr structured bindings for
C++23 and older instead of emitting error always, don't clear
constexpr_p in that case.
* parser.cc (cp_parser_decomposition_declaration): Copy over
DECL_DECLARED_CONSTEXPR_P and DECL_DECLARED_CONSTINIT_P flags.
* g++.dg/cpp1z/decomp3.C (test): For constexpr structured binding
initialize from constexpr var instead of non-constexpr and expect
just a pedwarn for C++23 and older instead of error always.
* g++.dg/cpp26/decomp9.C (foo): Likewise.
* g++.dg/cpp26/decomp22.C: New test.
* g++.dg/cpp26/decomp23.C: New test.
* g++.dg/cpp26/decomp24.C: New test.
* g++.dg/cpp26/decomp25.C: New test.
--- gcc/cp/decl.cc.jj 2025-06-17 13:19:02.989958992 +0200
+++ gcc/cp/decl.cc 2025-06-18 13:29:45.000000000 +0200
@@ -9170,6 +9170,10 @@ cp_finish_decl (tree decl, tree init, bo
if (decomp)
{
+ if (DECL_DECLARED_CONSTINIT_P (decl) && cxx_dialect < cxx26)
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+ "%<constinit%> can be applied to structured binding "
+ "only with %<-std=c++2c%> or %<-std=gnu++2c%>");
cp_maybe_mangle_decomp (decl, decomp);
if (TREE_STATIC (decl) && !DECL_FUNCTION_SCOPE_P (decl))
{
@@ -13612,9 +13616,10 @@ grokdeclarator (const cp_declarator *dec
if (typedef_p)
error_at (declspecs->locations[ds_typedef],
"structured binding declaration cannot be %qs", "typedef");
- if (constexpr_p && !concept_p)
- error_at (declspecs->locations[ds_constexpr], "structured "
- "binding declaration cannot be %qs", "constexpr");
+ if (constexpr_p && !concept_p && cxx_dialect < cxx26)
+ pedwarn (declspecs->locations[ds_constexpr], OPT_Wc__26_extensions,
+ "structured binding declaration can be %qs only with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", "constexpr");
if (consteval_p)
error_at (declspecs->locations[ds_consteval], "structured "
"binding declaration cannot be %qs", "consteval");
@@ -13625,8 +13630,11 @@ grokdeclarator (const cp_declarator *dec
declspecs->gnu_thread_keyword_p
? "__thread" : "thread_local");
if (concept_p)
- error_at (declspecs->locations[ds_concept],
- "structured binding declaration cannot be %qs", "concept");
+ {
+ error_at (declspecs->locations[ds_concept],
+ "structured binding declaration cannot be %qs", "concept");
+ constexpr_p = 0;
+ }
/* [dcl.struct.bind] "A cv that includes volatile is deprecated." */
if (type_quals & TYPE_QUAL_VOLATILE)
warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile,
@@ -13681,7 +13689,6 @@ grokdeclarator (const cp_declarator *dec
"%<auto%> type %qT", type);
inlinep = 0;
typedef_p = 0;
- constexpr_p = 0;
consteval_p = 0;
concept_p = 0;
if (storage_class != sc_static)
--- gcc/cp/parser.cc.jj 2025-06-17 13:19:03.011958702 +0200
+++ gcc/cp/parser.cc 2025-06-18 14:21:09.737238038 +0200
@@ -16859,7 +16859,11 @@ cp_parser_decomposition_declaration (cp_
decl = error_mark_node;
}
else
- prev = decl2;
+ {
+ prev = decl2;
+ DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl);
+ DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl);
+ }
if (elt_pushed_scope)
pop_scope (elt_pushed_scope);
}
--- gcc/testsuite/g++.dg/cpp1z/decomp3.C.jj 2020-01-12 11:54:37.128402621
+0100
+++ gcc/testsuite/g++.dg/cpp1z/decomp3.C 2025-06-18 14:10:48.777240454
+0200
@@ -19,7 +19,8 @@ test (A &b, B c)
// { dg-error "expected primary-expression before
'decltype'" "" { target c++11_down } .-2 }
auto & & && & [ m, n, o ] = b; // { dg-error "multiple ref-qualifiers" }
// { dg-warning "structured bindings only available
with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
- constexpr auto [ p ] = c; // { dg-error "structured binding
declaration cannot be 'constexpr'" }
+ constexpr B c2 = { 42 };
+ constexpr auto [ p ] = c2; // { dg-warning "structured binding declaration can be
'constexpr' only with" "" { target c++23_down } }
// { dg-warning "structured bindings only available
with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
friend auto [ q ] = c; // { dg-error "'friend' used outside of
class" }
// { dg-warning "structured bindings only available
with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 }
--- gcc/testsuite/g++.dg/cpp26/decomp9.C.jj 2024-07-02 22:07:20.601118378
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp9.C 2025-06-18 14:10:48.871239228
+0200
@@ -63,6 +63,7 @@ foo (const S &&s)
if (static auto [i, j, k] = t) // { dg-warning "structured bindings in
conditions only available with" "" { target c++23_down } }
; // { dg-error "'static' invalid in
condition" "" { target *-*-* } .-1 }
// { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
- if (constexpr auto [i, j, k] = t) // { dg-warning "structured bindings in
conditions only available with" "" { target c++23_down } }
- ; // { dg-error "structured binding declaration
cannot be 'constexpr'" "" { target *-*-* } .-1 }
+ constexpr T t2 = { 1, 2, 3 };
+ if (constexpr auto [i, j, k] = t2) // { dg-warning "structured bindings in
conditions only available with" "" { target c++23_down } }
+ ; // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
}
--- gcc/testsuite/g++.dg/cpp26/decomp22.C.jj 2025-06-18 14:31:25.279351164
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp22.C 2025-06-18 16:08:01.121464753
+0200
@@ -0,0 +1,66 @@
+// C++26 P2686R4 - constexpr structured bindings
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct A {
+ int i, j;
+ template <int I> constexpr const int &get () const { return I == 1 ? j : i; }
+};
+
+template <> struct std::tuple_size <const A> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, const A> { using type = const
int; };
+
+constexpr struct B {
+ int i, j;
+ long long k, l;
+} a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
+
+constexpr auto [ b, c, d ] = a; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only
available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11,
"");
+static_assert (h == 5 && i == 6 && j == 7 && k == 8, "");
+static_assert (p.i == 1 && p.l == 4 && q.j == 6 && q.k == 7 && r.i == 9 && r.k == 11,
"");
+static_assert (&p.i == &a[0].i && &p.l == &a[0].l && &q.j == &a[1].j, "");
+static_assert (&q.k == &a[1].k && &r.i == &a[2].i && &r.k == &a[2].k, "");
+static_assert (v == 5 && w == 6 && x == 7 && y == 8, "");
+static_assert (&v == &a[1].i && &w == &a[1].j && &x == &a[1].k && &y == &a[1].l,
"");
+
+constexpr A z = { 42, -42 };
+constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+static_assert (ae == 42 && af == -42 && ag == 42, "");
+static_assert (&af == &ae + 1 && &ag == &ae, "");
+static_assert (&ae != &z.i && &af != &z.j && &ag != &z.i, "");
+static_assert (ak == 42 && al == -42 && am == 42, "");
+static_assert (&ak == &z.i && &al == &z.j && &am == &z.i, "");
--- gcc/testsuite/g++.dg/cpp26/decomp23.C.jj 2025-06-18 15:18:03.497229175
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp23.C 2025-06-18 16:08:08.084374641
+0200
@@ -0,0 +1,77 @@
+// C++26 P2686R4 - constexpr structured bindings
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct A {
+ int i, j;
+ template <int I> constexpr const int &get () const { return I == 1 ? j : i; }
+};
+
+template <> struct std::tuple_size <const A> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, const A> { using type = const
int; };
+
+struct B {
+ int i, j;
+ long long k, l;
+};
+
+void
+foo ()
+{
+ static constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12
} };
+ static constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only
available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured bindings only
available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11,
"");
+ static_assert (h == 5 && i == 6 && j == 7 && k == 8, "");
+ static_assert (p.i == 1 && p.l == 4 && q.j == 6 && q.k == 7 && r.i == 9 && r.k == 11,
"");
+ static_assert (&p.i == &a[0].i && &p.l == &a[0].l && &q.j == &a[1].j, "");
+ static_assert (&q.k == &a[1].k && &r.i == &a[2].i && &r.k == &a[2].k, "");
+ static_assert (v == 5 && w == 6 && x == 7 && y == 8, "");
+ static_assert (&v == &a[1].i && &w == &a[1].j && &x == &a[1].k && &y == &a[1].l,
"");
+
+ static constexpr A z = { 42, -42 };
+ static constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-warning "structured binding
declaration can be 'static' only in" "" { target c++17_down } .-2 }
+#if __cpp_constinit >= 201907
+ static constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+ static_assert (ae == 42 && af == -42 && ag == 42, "");
+ static_assert (&af == &ae + 1 && &ag == &ae, "");
+ static_assert (&ae != &z.i && &af != &z.j && &ag != &z.i, "");
+ static_assert (ak == 42 && al == -42 && am == 42, "");
+ static_assert (&ak == &z.i && &al == &z.j && &am == &z.i, "");
+}
--- gcc/testsuite/g++.dg/cpp26/decomp24.C.jj 2025-06-18 15:50:44.408876408
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp24.C 2025-06-18 16:08:14.885286620
+0200
@@ -0,0 +1,20 @@
+// C++26 P2686R4 - constexpr structured bindings
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct B {
+ int i, j;
+ long long k, l;
+};
+
+void
+foo ()
+{
+ constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
+ constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11,
"");
+ static_assert (h == 5 && i == 6 && j == 7 && k == 8, "");
+}
--- gcc/testsuite/g++.dg/cpp26/decomp25.C.jj 2025-06-18 16:09:05.732628546
+0200
+++ gcc/testsuite/g++.dg/cpp26/decomp25.C 2025-06-18 17:05:01.682431174
+0200
@@ -0,0 +1,119 @@
+// C++26 P2686R4 - constexpr structured bindings
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+namespace std {
+ template <typename T> struct tuple_size;
+ template <int, typename> struct tuple_element;
+}
+
+struct A {
+ int i, j;
+ template <int I> int &get () { return I == 1 ? j : i; }
+};
+
+template <> struct std::tuple_size <A> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, A> { using type = int; };
+template <> struct std::tuple_size <const A> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, const A> { using type = int; };
+
+struct B {
+ int i, j;
+ long long k, l;
+} a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; // { dg-message "'a'
was not declared 'constexpr'" "" }
+
+struct C {
+ int i, j;
+ template <int I> const int &get () const { return I == 1 ? j : i; }
+};
+
+template <> struct std::tuple_size <const C> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, const C> { using type = const
int; };
+
+constexpr auto [ b, c, d ] = a; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "the value of 'a' is not
usable in a constant expression" "" { target *-*-* } .-2 }
+#if __cpp_constinit >= 201907
+constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "'constinit' variable
'<structured bindings>' does not have a constant initializer" "" { target c++20 }
.-1 }
+ // { dg-error "the value of 'a' is not
usable in a constant expression" "" { target c++20 } .-2 }
+#endif
+constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "the value of 'a' is not
usable in a constant expression" "" { target *-*-* } .-2 }
+#if __cpp_constinit >= 201907
+constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "'constinit' variable
'<structured bindings>' does not have a constant initializer" "" { target c++20 }
.-1 }
+ // { dg-error "the value of 'a' is not
usable in a constant expression" "" { target c++20 } .-2 }
+#endif
+constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only
available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+#if __cpp_constinit >= 201907
+constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+#endif
+
+A z = { 42, -42 }; // { dg-message "'z' was not declared
'constexpr'" "" }
+constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "the value of 'z' is not
usable in a constant expression" "" { target *-*-* } .-2 }
+ // { dg-error "passing 'const A' as
'this' argument discards qualifiers" "" { target *-*-* } .-3 }
+ // { dg-error "call to non-'constexpr'
function 'int\\\& A::get\\\(\\\)" "" { target *-*-* } .-4 }
+#if __cpp_constinit >= 201907
+constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "'constinit' variable
'<structured bindings>' does not have a constant initializer" "" { target c++20 }
.-1 }
+ // { dg-error "the value of 'z' is not
usable in a constant expression" "" { target c++20 } .-2 }
+ // { dg-error "passing 'const A' as
'this' argument discards qualifiers" "" { target c++20 } .-3 }
+ // { dg-error "call to non-'constexpr'
function 'int\\\& A::get\\\(\\\)" "" { target c++20 } .-4 }
+ // { dg-error "'constinit' variable
'ah' does not have a constant initializer" "" { target c++20 } .-5 }
+ // { dg-error "'constinit' variable
'ai' does not have a constant initializer" "" { target c++20 } .-6 }
+ // { dg-error "'constinit' variable
'aj' does not have a constant initializer" "" { target c++20 } .-7 }
+#endif
+constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "call to non-'constexpr'
function 'int\\\& A::get\\\(\\\)" "" { target *-*-* } .-2 }
+#if __cpp_constinit >= 201907
+constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "'constinit' variable
'an' does not have a constant initializer" "" { target c++20 } .-1 }
+ // { dg-error "'constinit' variable
'ao' does not have a constant initializer" "" { target c++20 } .-2 }
+ // { dg-error "'constinit' variable
'ap' does not have a constant initializer" "" { target c++20 } .-3 }
+ // { dg-message "call to non-'constexpr'
function 'int\\\& A::get\\\(\\\)" "" { target c++20 } .-4 }
+#endif
+
+constexpr C zz = { 42, -42 };
+constexpr auto [ aq, ar, as ] = zz; // { dg-warning "structured bindings
only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "call to non-'constexpr'
function 'const int\\\& C::get\\\(\\\) const" "" { target *-*-* } .-2 }
+#if __cpp_constinit >= 201907
+constinit const auto [ at, au, av ] = zz; // { dg-warning "'constinit' can be applied to
structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "call to non-'constexpr'
function 'const int\\\& C::get\\\(\\\) const" "" { target c++20 } .-1 }
+ // { dg-error "'constinit' variable
'at' does not have a constant initializer" "" { target c++20 } .-2 }
+ // { dg-error "'constinit' variable
'au' does not have a constant initializer" "" { target c++20 } .-3 }
+ // { dg-error "'constinit' variable
'av' does not have a constant initializer" "" { target c++20 } .-4 }
+#endif
+constexpr auto & [ aw, ax, ay ] = zz; // { dg-warning "structured
bindings only available with" "" { target c++14_down } }
+ // { dg-warning "structured binding
declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+ // { dg-error "call to non-'constexpr'
function 'const int\\\& C::get\\\(\\\) const" "" { target *-*-* } .-2 }
+#if __cpp_constinit >= 201907
+constinit auto & [ az, ba, bb ] = zz; // { dg-warning "'constinit' can be
applied to structured binding only with" "" { target { c++20 && c++23_down } } }
+ // { dg-error "'constinit' variable
'az' does not have a constant initializer" "" { target c++20 } .-1 }
+ // { dg-error "'constinit' variable
'ba' does not have a constant initializer" "" { target c++20 } .-2 }
+ // { dg-error "'constinit' variable
'bb' does not have a constant initializer" "" { target c++20 } .-3 }
+ // { dg-message "call to non-'constexpr'
function 'const int\\\& C::get\\\(\\\) const" "" { target c++20 } .-4 }
+#endif
+
+void
+foo ()
+{
+#if __cpp_constinit >= 201907
+ constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
+ constinit auto [ b, c, d ] = a; // { dg-error "'constinit' can only be
applied to a variable with static or thread storage duration" "" { target c++20 } }
+ constinit auto & [ e, f, g ] = a; // { dg-error "'constinit' can
only be applied to a variable with static or thread storage duration" "" { target c++20
} }
+ constinit auto [ h, i, j, k ] = a[1]; // { dg-error "'constinit' can
only be applied to a variable with static or thread storage duration" "" { target
c++20 } }
+ constinit auto & [ l, m, n, o ] = a[2]; // { dg-error "'constinit' can only be
applied to a variable with static or thread storage duration" "" { target c++20 } }
+#endif
+}
Jakub