c++: Implement mangling for partially instantiated C++26 pack indexing [PR124487]

Message ID adSs_VOA_quE5FWd@tucnak
State New
Headers
Series c++: Implement mangling for partially instantiated C++26 pack indexing [PR124487] |

Commit Message

Jakub Jelinek April 7, 2026, 7:06 a.m. UTC
  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

Jason Merrill April 7, 2026, 3:33 p.m. UTC | #1
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
>
  

Patch

--- 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>();
 }