On Wed, Aug 06, 2025 at 11:53:55AM -0700, Jason Merrill wrote: > > And one thing still unresolved is debug info, I've just added DECL_IGNORED_P > > on the structured binding pack VAR_DECL because there were ICEs with -g > > for now, hope it can be fixed incrementally but am not sure what exactly > > we should emit in the debug info for that. > > 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-07 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. --- gcc/cp/decl.cc.jj 2025-08-07 09:29:37.056498988 +0200 +++ gcc/cp/decl.cc 2025-08-07 15:53:48.167219127 +0200 @@ -10223,14 +10223,6 @@ cp_finish_decomp (tree decl, cp_decomp * "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 * 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; --- gcc/testsuite/g++.dg/cpp26/decomp19.C.jj 2025-08-07 09:13:54.501195628 +0200 +++ gcc/testsuite/g++.dg/cpp26/decomp19.C 2025-08-07 16:18:22.449507549 +0200 @@ -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 --- gcc/testsuite/g++.dg/cpp26/decomp26.C.jj 2025-08-07 16:18:39.548289896 +0200 +++ gcc/testsuite/g++.dg/cpp26/decomp26.C 2025-08-07 16:29:21.129123164 +0200 @@ -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> (); +} Jakub