From: Jakub Jelinek Date: Wed, 8 Apr 2026 05:46:38 +0000 (+0200) Subject: c++: Implement CWG3135 - constexpr structured bindings with prvalues from tuples X-Git-Tag: basepoints/gcc-17~284 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7e4e9dd9eb01de7bf9fc7abe82e9ab01123283cc;p=thirdparty%2Fgcc.git c++: Implement CWG3135 - constexpr structured bindings with prvalues from tuples 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 * 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 --- diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 930253d9646..ac74f4930e2 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -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 (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 (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 index 00000000000..f1e100e0f2b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp30.C @@ -0,0 +1,35 @@ +// CWG3135 - constexpr structured bindings with prvalues from tuples +// { dg-do compile { target c++14 } } +// { dg-options "" } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + template constexpr int get () const { return I + 6; } +}; + +template <> struct std::tuple_size { static const int value = 2; }; +template struct std::tuple_element { using type = int; }; +template <> struct std::tuple_size { static const int value = 2; }; +template struct std::tuple_element { using type = const int; }; + +constexpr A +bar () +{ + return A {}; +} + +template +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); diff --git a/gcc/testsuite/g++.dg/gomp/pr108503.C b/gcc/testsuite/g++.dg/gomp/pr108503.C index 906d41b9a8f..5c6c08ba0cb 100644 --- a/gcc/testsuite/g++.dg/gomp/pr108503.C +++ b/gcc/testsuite/g++.dg/gomp/pr108503.C @@ -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 } +}