<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/56099>56099</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Clang: Incomplete representation of type sugar for expanded argument packs in the AST.
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang:frontend
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
mizvekov
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
mizvekov
</td>
</tr>
</table>
<pre>
When expanding template argument packs, clang does not synthesize TemplateTypeParmTypes for the SubstTemplateTypeParmTypes which correspond to the argument's position in the expanded form.
Consider example 1: https://godbolt.org/z/KvMTbh5T7
```C++
template <typename... As> struct Y;
template <typename ...Bs> using Z = Y<Bs...>;
template <typename ...Cs> struct foo {
template <typename ...Ds> using bind = Z<Ds..., Cs...>;
};
using U = foo<int, short>::bind<char, float>;
```
AST:
```
TemplateSpecializationType 0x559e6e0cafa0 'Y<char, float, int, short>' sugar Y
|-TemplateArgument type 'char':'char'
| `-SubstTemplateTypeParmType 0x559e6e0cada0 'char' sugar
| |-TemplateTypeParmType 0x559e6e0acb60 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x559e6e0acb08 'Bs'
| `-BuiltinType 0x559e6e066e80 'char'
|-TemplateArgument type 'float':'float'
| `-SubstTemplateTypeParmType 0x559e6e0cade0 'float' sugar
| |-TemplateTypeParmType 0x559e6e0acb60 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x559e6e0acb08 'Bs'
| `-BuiltinType 0x559e6e066fe0 'float'
|-TemplateArgument type 'int':'int'
| `-SubstTemplateTypeParmType 0x559e6e0ca810 'int' sugar
| |-TemplateTypeParmType 0x559e6e0acb60 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x559e6e0acb08 'Bs'
| `-BuiltinType 0x559e6e066ee0 'int'
|-TemplateArgument type 'short':'short'
| `-SubstTemplateTypeParmType 0x559e6e0ca850 'short' sugar
| |-TemplateTypeParmType 0x559e6e0acb60 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x559e6e0acb08 'Bs'
| `-BuiltinType 0x559e6e066ec0 'short'
`-RecordType 0x559e6e0caf80 'Y<char, float, int, short>'
`-ClassTemplateSpecialization 0x559e6e0cae98 'Y'
```
Example 2: https://godbolt.org/z/r7v8hYdKx
```C++
template<typename ...T> struct D {
template<typename... U> using B = int(int (*...p)(T, U));
template<typename U1, typename U2> D(B<U1, U2>*);
};
using foo = D<float, char>::B<int, short>;
```
AST:
```
FunctionProtoType 0x564b6179e8e0 'int (int (*)(float, int), int (*)(char, short))' cdecl
|-BuiltinType 0x564b61738ee0 'int'
|-PointerType 0x564b6179e620 'int (*)(float, int)'
| `-ParenType 0x564b6179e5c0 'int (float, int)' sugar
| `-FunctionProtoType 0x564b6179e580 'int (float, int)' cdecl
| |-BuiltinType 0x564b61738ee0 'int'
| |-SubstTemplateTypeParmType 0x564b6179cef0 'float' sugar
| | |-TemplateTypeParmType 0x564b6177e6b0 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
| | | `-TemplateTypeParm 0x564b6177e630 'T'
| | `-BuiltinType 0x564b61738fe0 'float'
| `-SubstTemplateTypeParmType 0x564b6179e500 'int' sugar
| |-TemplateTypeParmType 0x564b6179c750 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x564b6179c6f8 'U'
| `-BuiltinType 0x564b61738ee0 'int'
`-PointerType 0x564b6179e830 'int (*)(char, short)'
`-ParenType 0x564b6179e7d0 'int (char, short)' sugar
`-FunctionProtoType 0x564b6179e790 'int (char, short)' cdecl
|-BuiltinType 0x564b61738ee0 'int'
|-SubstTemplateTypeParmType 0x564b6179dd90 'char' sugar
| |-TemplateTypeParmType 0x564b6177e6b0 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
| | `-TemplateTypeParm 0x564b6177e630 'T'
| `-BuiltinType 0x564b61738e80 'char'
`-SubstTemplateTypeParmType 0x564b6179e710 'short' sugar
|-TemplateTypeParmType 0x564b6179c750 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
| `-TemplateTypeParm 0x564b6179c6f8 'U'
`-BuiltinType 0x564b61738ec0 'short'
```
The TemplateTypeParmType's used are the original ones from the packed template argument, and as such it's pretty hard to map these to the argument list as-written.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzlWFtvozgU_jXkxWpEoOHykIeETKXVaKVqm2rVeRkZ2wneITjCJtP21--xuQQIuU1Huw-t0gSwz3cO3znHfDgW9G32d8IyxF53OKM82yDFtrsUK4Zwvim2LFNoh8kPaTkRIimGCVQwiTKhkHzLVMIkf2doVRmt3nbsEedb_SvRWuQIZqCnIpZqeMrPhJMEEZHnTO5ERpESxqR2bjm-RDshueIiQzwzg2WwjGoH27FlLy17Xn5HIpOcshymYHDH0MRy5yhRaifhwHIe4LMRNBapGot8A2fv8P91_-cqTqYrv4Ly7PITWc5Cf8zVhhfLjRTEnuEtG4_HaA7IX5BUeUEUerHcM9MRzF-Y6YXUVH-DwaW2iRYShmDgonnU9rYWAll-ZYHQKZtly2XMgWPt9RtMWhqvkNio797yl81xafhsrMAj2HGdlwjJROTKWM3ho5FhjCQ414PrVGDVgaxZLU_nTyttNzRUV8rTjhGOU_6OdfJ1vSD7dToNmcdsgtfYRlAdL0c-4aAfoOMjWWxwDlxXXNV_lh_d1f7mdcFr8jR2ieubymlOjgEQRH53ssbbMdMy5gqqjGkIsBvXMBomsWfQoKIAizJIONXRE5EpzDP5vcjqRvmuW1hPUQmygR3KXuFXXzzp3dxUP4KOdztovJ9AAYRFwVPFe8nzPBa0ibgpKVWSq6w0Zx9KC7PbyJ84L-suEzclxjRdlZbq-CNJCSb2AfUTp4SxFg83JaRc_uqUNGcfSsrUbiN_5rSQDhNH9mD5FwNdQ4-eW8Etz60-bokcpVjK4cdk2xULg9KV01c2bc30pZJKzjVSKff3QfJCv75eI5V6OmTVki7LIeHSU1bPB9myMOrD0BPAN9xVYDlzmLSznBBOVpq2Z3McNopjEBg9T_Tcw6mjvSwBYwGzykFzDfDbYMeKyKgviAquR00GTUprSbQY0ko3y6GHIiM6s4-5UKKuJu8-9iZ-yIJmdUAdakpauoUVVkedKXUNVoVsCIRmJJSRtFt8uqF7zVBG4QZn1iht9ShghOX92D2nHfvpoI8RTRNAO7OsjzklbcxjqKEV69DrZ6meBheghzn7GHeN9dnluQqRsPVFIdPCPLtEl5A-82IDufptK3QvgJOrdBOA2wRwBuh4oa75PStpGoxLD8CmCOwLqqRGPP8ArBPml8_T59_O7vknYO3eWwe1-5Mwp5k9V7m6P4e7PnAHu_54HRp8pg42vU_bkANIwzrlip73w0vIA01_SP_txB1srylHSsPLL5T_a7d33P96r3dL-hStZ18q63xf1eb-5Aqde8jVf97mfUZ-qcnbrJyidEjlDqrIVTK8C2g28ArJKILONbt3IucbnuEUiUzvEeZiay7rm4RZR9uPuuGAG4QlZIEkiFd7gjlT6g1Brs2e4RbvNIpk_Q1ElHKpwPjuZ86VYtl4RGcuDd0QjxRXKZtFelNTS98_MiK0EAbfOQN4CdalpBbr8p2q3EPSu5rNDmR3k7TeoAQ1Nx4VeTrryWmukiIegxs4SdN9_XO3y8U_jMCNPXApCwYvJA9Tzw7DUTK7n8YhWVPbtz069b1JTNxgsvZYEOCY-p4zSnHMUjmzpqC_HVLdDLAKa29G4ZI1XY74zLEdx_YmgT1x721_TCbMDdfEZyEJXUpC695mW8zTsQ5Hy_1RPjORxcVGwqAmUR4G4e2DbzLGKq9b_r5nP8S-8oYLBfUyq6-OzD3NzA39C1Cpf2c">