c++: Implement mangling for partially instantiated C++26 pack indexing [PR124487]
Commit Message
On Fri, Apr 03, 2026 at 05:56:08PM -0400, Jason Merrill wrote:
> Regarding the TODO, the related case I was thinking about was
>
> > ::= sZ <template-param> # sizeof...(T), size of a template parameter pack
> > ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template
>
> ...but rather than follow the precedent of a different two-letter
> abbreviation, I might use J...E to express the expanded pack, as in
> <template-arg>. I've now suggested that on the ABI issue, as well.
Here is a patch which implements it.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-04-07 Jakub Jelinek <jakub@redhat.com>
* mangle.cc (write_type) <case PACK_INDEX_TYPE>: Handle even
the case of partially substituted pack.
(write_expression): Similarly for PACK_INDEX_EXPR.
* g++.dg/cpp26/pack-indexing9.C: Remove dg-sorry/dg-bogus, add
tests for mangled names and further test coverage.
Jakub
Comments
On 4/7/26 3:06 AM, Jakub Jelinek wrote:
> On Fri, Apr 03, 2026 at 05:56:08PM -0400, Jason Merrill wrote:
>> Regarding the TODO, the related case I was thinking about was
>>
>>> ::= sZ <template-param> # sizeof...(T), size of a template parameter pack
>>> ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template
>>
>> ...but rather than follow the precedent of a different two-letter
>> abbreviation, I might use J...E to express the expanded pack, as in
>> <template-arg>. I've now suggested that on the ABI issue, as well.
>
> Here is a patch which implements it.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK.
> 2026-04-07 Jakub Jelinek <jakub@redhat.com>
>
> * mangle.cc (write_type) <case PACK_INDEX_TYPE>: Handle even
> the case of partially substituted pack.
> (write_expression): Similarly for PACK_INDEX_EXPR.
>
> * g++.dg/cpp26/pack-indexing9.C: Remove dg-sorry/dg-bogus, add
> tests for mangled names and further test coverage.
>
> --- gcc/cp/mangle.cc.jj 2026-04-04 11:17:15.921287840 +0200
> +++ gcc/cp/mangle.cc 2026-04-06 09:14:12.484890203 +0200
> @@ -2745,16 +2745,19 @@ write_type (tree type)
>
> case PACK_INDEX_TYPE:
> /* https://github.com/itanium-cxx-abi/cxx-abi/issues/175. */
> + write_string ("Dy");
> if (TREE_CODE (PACK_INDEX_PACK (type)) == TREE_VEC)
> {
> - /* TODO: How should this be mangled when the pack is already
> - expanded? */
> - sorry ("mangling type pack index");
> - break;
> + write_char ('J');
> + for (int i = 0; i < TREE_VEC_LENGTH (PACK_INDEX_PACK (type));
> + ++i)
> + write_template_arg (TREE_VEC_ELT (PACK_INDEX_PACK (type),
> + i));
> + write_char ('E');
> }
> - write_string ("Dy");
> - /* Dy rather than DyDp. */
> - write_type (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (type)));
> + else
> + /* Dy rather than DyDp. */
> + write_type (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (type)));
> write_expression (PACK_INDEX_INDEX (type));
> break;
>
> @@ -3614,17 +3617,19 @@ write_expression (tree expr)
> else if (code == PACK_INDEX_EXPR)
> {
> /* https://github.com/itanium-cxx-abi/cxx-abi/issues/175. */
> + write_string ("sy");
> if (TREE_CODE (PACK_INDEX_PACK (expr)) == TREE_VEC)
> - /* TODO: How should this be mangled when the pack is already
> - expanded? */
> - sorry ("mangling type pack index");
> - else
> {
> - write_string ("sy");
> - /* sy rather than sysp. */
> - write_expression (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (expr)));
> - write_expression (PACK_INDEX_INDEX (expr));
> + write_char ('J');
> + for (int i = 0; i < TREE_VEC_LENGTH (PACK_INDEX_PACK (expr));
> + ++i)
> + write_template_arg (TREE_VEC_ELT (PACK_INDEX_PACK (expr), i));
> + write_char ('E');
> }
> + else
> + /* sy rather than sysp. */
> + write_expression (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (expr)));
> + write_expression (PACK_INDEX_INDEX (expr));
> }
> else if (TREE_CODE (expr) == ALIGNOF_EXPR)
> {
> --- gcc/testsuite/g++.dg/cpp26/pack-indexing9.C.jj 2026-03-27 10:17:15.656305903 +0100
> +++ gcc/testsuite/g++.dg/cpp26/pack-indexing9.C 2026-04-06 09:27:43.438279320 +0200
> @@ -4,24 +4,42 @@
> // From <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>.
>
> template <class... T> struct tuple {
> - template <unsigned I> T...[I] get(); // { dg-bogus "sorry, unimplemented: mangling" "" { xfail *-*-* } }
> + template <unsigned I> T...[I] get();
> };
>
> int
> g ()
> {
> tuple<int> t;
> + // { dg-final { scan-assembler "_ZN5tupleIJiEE3getILj0EEEDyJiET_v" } }
> return t.get<0>();
> }
>
> template<typename T, typename U> concept C = true;
> +template<typename T, auto U> concept D = true;
> template<typename ...T> struct A {
> - template<int I, typename ...U> void f(T...[I], U...[I]) requires C<T...[I], U...[I]>; // { dg-message "sorry, unimplemented: mangling" }
> + template<int I, typename ...U> void f(T...[I], U...[I]) requires C<T...[I], U...[I]>;
> + template<int I, auto ...U> void h(T...[I], decltype(U...[I])) requires D<T...[I], U...[I]>;
> };
>
> void
> h ()
> {
> A<char, int, double> a;
> + // { dg-final { scan-assembler "_ZN1AIJcidEE1fILi1EJiicEEEvDyJcidET_DyT0_T_Q1CIDyT_TL0__DyTL0_0_TL0__E" } }
> a.f<1, int, int, char>(1, 2);
> + // { dg-final { scan-assembler "_ZN1AIJcidEE1hILi1EJLi2ELl3ELj4EEEEvDyJcidET_DtsyT0_T_EQ1DIDyT_TL0__XsyTL0_0_TL0__EE" } }
> + a.h<1, 2, 3L, 4U>(1, 3L);
> +}
> +
> +template <auto... U> struct E {
> + template <unsigned I> decltype (U...[I]) get();
> +};
> +
> +int
> +i ()
> +{
> + E<1, 2L, 3U, 4LL> t;
> + // { dg-final { scan-assembler "_ZN1EIJLi1ELl2ELj3ELx4EEE3getILj2EEEDtsyJLi1ELl2ELj3ELx4EET_Ev" } }
> + return t.get<2>();
> }
>
>
> Jakub
>
@@ -2745,16 +2745,19 @@ write_type (tree type)
case PACK_INDEX_TYPE:
/* https://github.com/itanium-cxx-abi/cxx-abi/issues/175. */
+ write_string ("Dy");
if (TREE_CODE (PACK_INDEX_PACK (type)) == TREE_VEC)
{
- /* TODO: How should this be mangled when the pack is already
- expanded? */
- sorry ("mangling type pack index");
- break;
+ write_char ('J');
+ for (int i = 0; i < TREE_VEC_LENGTH (PACK_INDEX_PACK (type));
+ ++i)
+ write_template_arg (TREE_VEC_ELT (PACK_INDEX_PACK (type),
+ i));
+ write_char ('E');
}
- write_string ("Dy");
- /* Dy rather than DyDp. */
- write_type (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (type)));
+ else
+ /* Dy rather than DyDp. */
+ write_type (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (type)));
write_expression (PACK_INDEX_INDEX (type));
break;
@@ -3614,17 +3617,19 @@ write_expression (tree expr)
else if (code == PACK_INDEX_EXPR)
{
/* https://github.com/itanium-cxx-abi/cxx-abi/issues/175. */
+ write_string ("sy");
if (TREE_CODE (PACK_INDEX_PACK (expr)) == TREE_VEC)
- /* TODO: How should this be mangled when the pack is already
- expanded? */
- sorry ("mangling type pack index");
- else
{
- write_string ("sy");
- /* sy rather than sysp. */
- write_expression (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (expr)));
- write_expression (PACK_INDEX_INDEX (expr));
+ write_char ('J');
+ for (int i = 0; i < TREE_VEC_LENGTH (PACK_INDEX_PACK (expr));
+ ++i)
+ write_template_arg (TREE_VEC_ELT (PACK_INDEX_PACK (expr), i));
+ write_char ('E');
}
+ else
+ /* sy rather than sysp. */
+ write_expression (PACK_EXPANSION_PATTERN (PACK_INDEX_PACK (expr)));
+ write_expression (PACK_INDEX_INDEX (expr));
}
else if (TREE_CODE (expr) == ALIGNOF_EXPR)
{
@@ -4,24 +4,42 @@
// From <https://github.com/itanium-cxx-abi/cxx-abi/issues/175>.
template <class... T> struct tuple {
- template <unsigned I> T...[I] get(); // { dg-bogus "sorry, unimplemented: mangling" "" { xfail *-*-* } }
+ template <unsigned I> T...[I] get();
};
int
g ()
{
tuple<int> t;
+ // { dg-final { scan-assembler "_ZN5tupleIJiEE3getILj0EEEDyJiET_v" } }
return t.get<0>();
}
template<typename T, typename U> concept C = true;
+template<typename T, auto U> concept D = true;
template<typename ...T> struct A {
- template<int I, typename ...U> void f(T...[I], U...[I]) requires C<T...[I], U...[I]>; // { dg-message "sorry, unimplemented: mangling" }
+ template<int I, typename ...U> void f(T...[I], U...[I]) requires C<T...[I], U...[I]>;
+ template<int I, auto ...U> void h(T...[I], decltype(U...[I])) requires D<T...[I], U...[I]>;
};
void
h ()
{
A<char, int, double> a;
+ // { dg-final { scan-assembler "_ZN1AIJcidEE1fILi1EJiicEEEvDyJcidET_DyT0_T_Q1CIDyT_TL0__DyTL0_0_TL0__E" } }
a.f<1, int, int, char>(1, 2);
+ // { dg-final { scan-assembler "_ZN1AIJcidEE1hILi1EJLi2ELl3ELj4EEEEvDyJcidET_DtsyT0_T_EQ1DIDyT_TL0__XsyTL0_0_TL0__EE" } }
+ a.h<1, 2, 3L, 4U>(1, 3L);
+}
+
+template <auto... U> struct E {
+ template <unsigned I> decltype (U...[I]) get();
+};
+
+int
+i ()
+{
+ E<1, 2L, 3U, 4LL> t;
+ // { dg-final { scan-assembler "_ZN1EIJLi1ELl2ELj3ELx4EEE3getILj2EEEDtsyJLi1ELl2ELj3ELx4EET_Ev" } }
+ return t.get<2>();
}