Hi! 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.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 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. --- gcc/cp/pt.cc.jj 2025-08-23 15:51:08.726081054 +0200 +++ gcc/cp/pt.cc 2025-08-23 16:56:58.997154023 +0200 @@ -32834,11 +32834,6 @@ finish_expansion_stmt (tree expansion_st 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); @@ -32850,7 +32845,8 @@ finish_expansion_stmt (tree expansion_st = 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; @@ -32871,7 +32867,7 @@ finish_expansion_stmt (tree expansion_st 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; } --- gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C.jj 2025-08-15 22:38:29.076869994 +0200 +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt15.C 2025-08-23 17:05:32.182449214 +0200 @@ -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 } } --- gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C.jj 2025-08-23 17:08:16.771305746 +0200 +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt21.C 2025-08-23 17:08:48.477892823 +0200 @@ -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 (); +} --- gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C.jj 2025-08-23 17:08:25.082197512 +0200 +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt22.C 2025-08-23 17:12:29.452987817 +0200 @@ -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 } +} Jakub