https://gcc.gnu.org/g:c81447d969f27a8653ebb1a450372f0d25a2e628
commit r16-2108-gc81447d969f27a8653ebb1a450372f0d25a2e628 Author: Jakub Jelinek <ja...@redhat.com> Date: Tue Jul 8 19:21:55 2025 +0200 c++: Implement part of C++26 P2686R4 - constexpr structured bindings [PR117784] The following patch implements the constexpr structured bindings part of the P2686R4 paper, so the [dcl.pre], [dcl.struct.bind], [dcl.constinit] and first hunk in [dcl.constexpr] changes. The paper doesn't have a feature test macro and the constexpr structured binding part of it seems more-less self-contained, so I think it is useful to get this in independently from the rest. Of course, automatic constexpr/constinit structured bindings in the tuple cases or automatic constexpr/constinit structured bindings with auto & will not really work for now. Another reason for the split is that for C++ < 26, I think what the patch implements is basically what the users will see, i.e. we can accept constexpr or constinit structured binding with pedwarn, but I think we can't change the constant expression rules in C++ < 26. I plan to look at the rest of the paper. 2025-07-08 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. Diff: --- gcc/cp/decl.cc | 19 ++++-- gcc/cp/parser.cc | 6 +- gcc/testsuite/g++.dg/cpp1z/decomp3.C | 3 +- gcc/testsuite/g++.dg/cpp26/decomp22.C | 66 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/decomp23.C | 77 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/decomp24.C | 20 ++++++ gcc/testsuite/g++.dg/cpp26/decomp25.C | 119 ++++++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/decomp9.C | 5 +- 8 files changed, 305 insertions(+), 10 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index be26bd39b225..99b9854210f7 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -9174,6 +9174,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, 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)) { @@ -13621,9 +13625,10 @@ grokdeclarator (const cp_declarator *declarator, 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"); @@ -13634,8 +13639,11 @@ grokdeclarator (const cp_declarator *declarator, 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, @@ -13690,7 +13698,6 @@ grokdeclarator (const cp_declarator *declarator, "%<auto%> type %qT", type); inlinep = 0; typedef_p = 0; - constexpr_p = 0; consteval_p = 0; concept_p = 0; if (storage_class != sc_static) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 239e6f9a5565..32c6a42b31de 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16870,7 +16870,11 @@ cp_parser_decomposition_declaration (cp_parser *parser, 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); } diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp3.C b/gcc/testsuite/g++.dg/cpp1z/decomp3.C index a9b23b08d83a..202edc3f6c17 100644 --- a/gcc/testsuite/g++.dg/cpp1z/decomp3.C +++ b/gcc/testsuite/g++.dg/cpp1z/decomp3.C @@ -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 } diff --git a/gcc/testsuite/g++.dg/cpp26/decomp22.C b/gcc/testsuite/g++.dg/cpp26/decomp22.C new file mode 100644 index 000000000000..576a93b00a94 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp22.C @@ -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, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/decomp23.C b/gcc/testsuite/g++.dg/cpp26/decomp23.C new file mode 100644 index 000000000000..ad2f7e011049 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp23.C @@ -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, ""); +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp24.C b/gcc/testsuite/g++.dg/cpp26/decomp24.C new file mode 100644 index 000000000000..5da1321f97bd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp24.C @@ -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, ""); +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp25.C b/gcc/testsuite/g++.dg/cpp26/decomp25.C new file mode 100644 index 000000000000..55559f0c0c22 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp25.C @@ -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 +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp9.C b/gcc/testsuite/g++.dg/cpp26/decomp9.C index 5629c4c9d573..ee18b6045cb8 100644 --- a/gcc/testsuite/g++.dg/cpp26/decomp9.C +++ b/gcc/testsuite/g++.dg/cpp26/decomp9.C @@ -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 } }