https://gcc.gnu.org/g:05baaa6feb9a8093646113c95f4cb8590ddd6de8
commit r16-3369-g05baaa6feb9a8093646113c95f4cb8590ddd6de8 Author: Jakub Jelinek <ja...@redhat.com> Date: Mon Aug 25 16:29:17 2025 +0200 c++: Implement C++ CWG3048 - Empty destructuring expansion statements The following patch implements the proposed resolution of https://cplusplus.github.io/CWG/issues/3048.html Instead of rejecting structured binding size it just builds a normal decl rather than structured binding declaration. 2025-08-25 Jakub Jelinek <ja...@redhat.com> * pt.cc (finish_expansion_stmt): Implement C++ CWG3048 - Empty destructuring expansion statements. Don't error for destructuring expansion stmts if sz is 0, don't call fit_decomposition_lang_decl if n is 0 and pass NULL rather than this_decomp to cp_finish_decl. * g++.dg/cpp26/expansion-stmt15.C: Don't expect error on destructuring expansion stmts with structured binding size 0. * g++.dg/cpp26/expansion-stmt21.C: New test. * g++.dg/cpp26/expansion-stmt22.C: New test. Diff: --- gcc/cp/pt.cc | 10 +++------- gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C | 4 ++-- gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C | 24 ++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C | 16 ++++++++++++++++ 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index dfabc5437d8b..d628744dbfd1 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -32827,11 +32827,6 @@ finish_expansion_stmt (tree expansion_stmt, tree args, tf_warning_or_error); if (sz < 0) return; - if (sz == 0) - { - error_at (loc, "empty structured binding"); - return; - } n = sz; tree auto_node = make_auto (); tree decomp_type = cp_build_reference_type (auto_node, true); @@ -32843,7 +32838,8 @@ finish_expansion_stmt (tree expansion_stmt, tree args, = DECL_DECLARED_CONSTEXPR_P (range_decl); if (DECL_DECLARED_CONSTEXPR_P (decl)) TREE_READONLY (decl) = 1; - fit_decomposition_lang_decl (decl, NULL_TREE); + if (n) + fit_decomposition_lang_decl (decl, NULL_TREE); pushdecl (decl); cp_decomp this_decomp; this_decomp.count = n; @@ -32864,7 +32860,7 @@ finish_expansion_stmt (tree expansion_stmt, tree args, DECL_NAME (decl) = for_range__identifier; cp_finish_decl (decl, expansion_init, /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING, &this_decomp); + LOOKUP_ONLYCONVERTING, n ? &this_decomp : NULL); DECL_NAME (decl) = NULL_TREE; } diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C index 0c69afafa49f..87d14e4d5663 100644 --- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C @@ -27,11 +27,11 @@ foo (int n) int e = 42; d[0] = 42; template for (auto a : A {}) // { dg-warning "'template for' only available with" "" { target c++23_down } } - ; // { dg-error "empty structured binding" "" { target *-*-* } .-1 } + ; template for (int b : B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } } ; template for (int i : c) // { dg-warning "'template for' only available with" "" { target c++23_down } } - ; // { dg-error "empty structured binding" "" { target *-*-* } .-1 } + ; template for (int i : d) // { dg-warning "'template for' only available with" "" { target c++23_down } } ; // { dg-error "cannot decompose variable length array" "" { target *-*-* } .-1 } template for (auto a : C {}) // { dg-warning "'template for' only available with" "" { target c++23_down } } diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C new file mode 100644 index 000000000000..59e1ca5ec389 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C @@ -0,0 +1,24 @@ +// DR3048 - Empty destructuring expansion statements +// { dg-do run { target c++11 } } +// { dg-options "" } + +struct A {}; + +int +foo () +{ + int c[0] = {}; + int r = 0; + template for (auto a : A {}) // { dg-warning "'template for' only available with" "" { target c++23_down } } + ++r; + template for (int i : c) // { dg-warning "'template for' only available with" "" { target c++23_down } } + ++r; + return r; +} + +int +main () +{ + if (foo () != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C new file mode 100644 index 000000000000..b0558d0d96dd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C @@ -0,0 +1,16 @@ +// DR3048 - Empty destructuring expansion statements +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct A {}; + +void +foo () +{ + static constexpr A b {}; + template for (constexpr auto a : b) // { dg-warning "'template for' only available with" "" { target c++23_down } } + ; + A c {}; + template for (constexpr auto a : c) // { dg-warning "'template for' only available with" "" { target c++23_down } } + ; // { dg-error "'c' is not a constant expression" "" { target *-*-* } .-1 } +}