On 8/7/25 11:04 AM, Jakub Jelinek wrote:
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.
OK.
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