https://gcc.gnu.org/g:5274f490fa72830aafd278bc752145f1225b08e0
commit r16-3121-g5274f490fa72830aafd278bc752145f1225b08e0 Author: Jakub Jelinek <ja...@redhat.com> Date: Mon Aug 11 08:54:57 2025 +0200 c++: Implement mangling for structured binding packs [PR117783] On Wed, Aug 06, 2025 at 11:53:55AM -0700, Jason Merrill wrote: > The Clang mangling of the underlying variable seems fine, just mentioning > the bound names; we can't get mangling collisions between pack and non-pack > versions of the same name. > > But It looks like they use .N discriminators for the individual elements, > which is wrong because . is reserved for implementation details. But I'd > think it should be fine to use [<discriminator>] instead. If you want the whole structured bindings to be mangled normally as if the pack isn't a pack and the individual vars of the structured binding pack mangled as multiple occurrences of the named entities, the following patch does that. 2025-08-11 Jakub Jelinek <ja...@redhat.com> PR c++/117783 * decl.cc (cp_finish_decomp): Don't sorry on tuple static structured bindings with a pack, instead temporarily reset DECL_NAME of the individual vars in the pack to the name of the pack for cp_finish_decl time and force mangling. * g++.dg/cpp26/decomp19.C: Don't expect sorry on tuple static structured bindings with a pack. * g++.dg/cpp26/decomp26.C: New test. Diff: --- gcc/cp/decl.cc | 16 ++++---- gcc/testsuite/g++.dg/cpp26/decomp19.C | 2 - gcc/testsuite/g++.dg/cpp26/decomp26.C | 77 +++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index ab5b0c974886..693cf65fd012 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10223,14 +10223,6 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) "pack %qD", v[pack]); goto error_out; } - if (j == 0 - && !processing_template_decl - && TREE_STATIC (decl)) - { - sorry_at (dloc, "mangling of structured binding pack " - "elements not implemented yet"); - goto error_out; - } maybe_push_decl (t); /* Save the decltype away before reference collapse. */ hash_map_safe_put<hm_ggc> (decomp_type_table, t, eltype); @@ -10241,8 +10233,16 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p) if (!processing_template_decl) { copy_linkage (t, decl); + tree name = DECL_NAME (t); + if (TREE_STATIC (decl)) + DECL_NAME (t) = DECL_NAME (v[pack]); cp_finish_decl (t, init, /*constexpr*/false, /*asm*/NULL_TREE, LOOKUP_NORMAL); + if (TREE_STATIC (decl)) + { + DECL_ASSEMBLER_NAME (t); + DECL_NAME (t) = name; + } } } continue; diff --git a/gcc/testsuite/g++.dg/cpp26/decomp19.C b/gcc/testsuite/g++.dg/cpp26/decomp19.C index b4d97a154560..3cec3c5d0072 100644 --- a/gcc/testsuite/g++.dg/cpp26/decomp19.C +++ b/gcc/testsuite/g++.dg/cpp26/decomp19.C @@ -24,7 +24,6 @@ foo () static auto [ta, ...tb, tc] = t; // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } } // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } - // { dg-message "mangling of structured binding pack elements not implemented yet" "" { target *-*-* } .-3 } } template <int N> @@ -35,7 +34,6 @@ bar () thread_local auto [...ta] = t; // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } } // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } .-2 } - // { dg-message "mangling of structured binding pack elements not implemented yet" "" { target *-*-* } .-3 } } int diff --git a/gcc/testsuite/g++.dg/cpp26/decomp26.C b/gcc/testsuite/g++.dg/cpp26/decomp26.C new file mode 100644 index 000000000000..24865ca7e56c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp26.C @@ -0,0 +1,77 @@ +// P1061R10 - Structured Bindings can introduce a Pack +// { dg-do compile { target c++11 } } +// { dg-options "" } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1a:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1b:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1c:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1a_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1b_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1c_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivEDC1a1b1cE:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1a_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1b_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1AEivE1c_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1a:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1c:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1a_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1c_0:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivEDC1a1b1cE:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1a_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b_2:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b_3:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1c_1:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1a_2:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1b_4:" } } +// { dg-final { scan-assembler "_ZZ3fooI1BEivE1c_2:" } } + +template <typename T> +int +foo () +{ + static int a = 1, b = 2, c = 3; + int d = a++ + b++ + c++; + { + static int a = 1, b = 2, c = 3; + d += a++ + b++ + c++; + { + static auto [a, ...b, c] = T {}; // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } + d += a++ + b...[0]++ + c++; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + { + static int a = 1, b = 2, c = 3; + return d + a++ + b++ + c++; + } + } + } +} + +struct A { int a, b, c, d, e; }; + +void +bar () +{ + foo <A> (); +} + +namespace std { + template<typename T> struct tuple_size; + template<int, typename> struct tuple_element; +} + +struct B { + int a[5]; + template <int I> int &get () { return a[I]; } +}; + +template<> struct std::tuple_size<B> { static const int value = 5; }; +template<int I> struct std::tuple_element<I,B> { using type = int; }; + +void +baz () +{ + foo <B> (); +}