]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Implement CWG3135 - constexpr structured bindings with prvalues from tuples
authorJakub Jelinek <jakub@redhat.com>
Wed, 8 Apr 2026 05:46:38 +0000 (07:46 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 8 Apr 2026 05:46:38 +0000 (07:46 +0200)
The following patch implements another CWG issue, added e.g. for the
P1789R3 (Library Support for Expansion Statements) APIs where get returns
a prvalue rather than a reference.

While the issue has been voted as a non-DR, this implementation assumes it
will be changed to a DR.  If that won't be the case, we will need to limit
the changes to C++26 and later only.

The gomp testcase was using get returning prvalue and the changes
cause some changes in lines on which stuff is reported.

2026-04-08  Jakub Jelinek  <jakub@redhat.com>

* decl.cc (cp_finish_decomp): Implement CWG3135 - constexpr structured
bindings with prvalues from tuples (as a DR).  Don't call
cp_build_reference_type if init is prvalue.

* g++.dg/cpp26/decomp30.C: New test.
* g++.dg/gomp/pr108503.C: Adjust expected diagnostic locations.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/decl.cc
gcc/testsuite/g++.dg/cpp26/decomp30.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/pr108503.C

index 930253d964605c5a7ea73e98e57ed09fbdad7bb0..ac74f4930e2b0dd526b0b48ea17199043b9c3c18 100644 (file)
@@ -11025,7 +11025,8 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
                  maybe_push_decl (t);
                  /* Save the decltype away before reference collapse.  */
                  hash_map_safe_put<hm_ggc> (decomp_type_table, t, eltype);
-                 eltype = cp_build_reference_type (eltype, !lvalue_p (init));
+                 if (glvalue_p (init))
+                   eltype = cp_build_reference_type (eltype, !lvalue_p (init));
                  TREE_TYPE (t) = eltype;
                  layout_decl (t, 0);
                  DECL_HAS_VALUE_EXPR_P (t) = 0;
@@ -11070,7 +11071,8 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
            }
          /* Save the decltype away before reference collapse.  */
          hash_map_safe_put<hm_ggc> (decomp_type_table, v[i], eltype);
-         eltype = cp_build_reference_type (eltype, !lvalue_p (init));
+         if (glvalue_p (init))
+           eltype = cp_build_reference_type (eltype, !lvalue_p (init));
          TREE_TYPE (v[i]) = eltype;
          layout_decl (v[i], 0);
          if (DECL_HAS_VALUE_EXPR_P (v[i]))
diff --git a/gcc/testsuite/g++.dg/cpp26/decomp30.C b/gcc/testsuite/g++.dg/cpp26/decomp30.C
new file mode 100644 (file)
index 0000000..f1e100e
--- /dev/null
@@ -0,0 +1,35 @@
+// CWG3135 - constexpr structured bindings with prvalues from tuples
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+namespace std {
+  template <typename T> struct tuple_size;
+  template <int, typename> struct tuple_element;
+}
+
+struct A {
+  template <int I> constexpr int get () const { return I + 6; }
+};
+
+template <> struct std::tuple_size <A> { static const int value = 2; };
+template <int I> struct std::tuple_element <I, A> { using type = int; };
+template <> struct std::tuple_size <const A> { static const int value = 2; };
+template <int I> struct std::tuple_element <I, const A> { using type = const int; };
+
+constexpr A
+bar ()
+{
+  return A {};
+}
+
+template <int N>
+constexpr int
+foo ()
+{
+  constexpr auto [...i] = bar ();      // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } }
+                                       // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 }
+                                       // { dg-warning "structured bindings only available with" "" { target c++14_down } .-2 }
+  return i...[0] + i...[1];            // { dg-warning "pack indexing only available with" "" { target c++23_down } }
+}
+
+static_assert (foo <42> () == 13);
index 906d41b9a8ff0b534f4cb9cab207546a90c3ae1c..5c6c08ba0cbcbaafa5f59b057ab569e05daacdb6 100644 (file)
@@ -21,7 +21,7 @@ void
 foo (B a)
 {
   #pragma omp for collapse(2)
-  for (auto [i, j, k] : a)
-    for (int l = i; l < j; l += k)     // { dg-error "initializer expression refers to iteration variable 'i'" }
-      ;                                        // { dg-error "condition expression refers to iteration variable 'j'" "" { target *-*-* } .-1 }
-}                                      // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-2 }
+  for (auto [i, j, k] : a)             // { dg-error "initializer expression refers to iteration variable 'i'" }
+    for (int l = i; l < j; l += k)     // { dg-error "condition expression refers to iteration variable 'j'" }
+      ;                                        // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-2 }
+}