https://gcc.gnu.org/g:7e4e9dd9eb01de7bf9fc7abe82e9ab01123283cc
commit r16-8520-g7e4e9dd9eb01de7bf9fc7abe82e9ab01123283cc Author: Jakub Jelinek <[email protected]> Date: Wed Apr 8 07:46:38 2026 +0200 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 <[email protected]> * 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 <[email protected]> Diff: --- gcc/cp/decl.cc | 6 ++++-- gcc/testsuite/g++.dg/cpp26/decomp30.C | 35 +++++++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/pr108503.C | 8 ++++---- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 930253d96460..ac74f4930e2b 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<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 index 000000000000..f1e100e0f2b8 --- /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 <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); diff --git a/gcc/testsuite/g++.dg/gomp/pr108503.C b/gcc/testsuite/g++.dg/gomp/pr108503.C index 906d41b9a8ff..5c6c08ba0cbc 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 } +}
