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 }
 }

Reply via email to