Clang rejects the following valid code:
template <class T> struct Foo {}; template <class... Ts> using FooAlias = Foo<void(Ts...)>; template <class... Ts> int bar(FooAlias<Ts...>); int main() { bar(FooAlias<>()); }
The problem is that in the substitution of FooAlias<Ts...> during the parsing of bar, the pack expansion in Foo<void(Ts...)> is transformed into a parameter with the unexpanded flag set, as opposed to another pack expansion. This leads to deduction failing in main, which is incorrect. The fix is to expand the parameter pack when needed.
Fixes PR25250 & PR26017.
Incidentally, there was an incorrect comment in a very similar function that said that a path wasn't reachable. This isn't the case, although no existing test case exercised it, so I added one that did. Please let me know if it would be cleaner to commit that separately!
Thanks!
Any thoughts on the value of threading EllipsisLoc and PatternRange into this function (they are used primarily for a diagnostic that is triggered in Sema if NewType does not contain an unexpandedparameter pack - which would never get triggered here, so it would be ok to pass in invalid sourelocations and sourceranges with an appropriate comment here) - but the fact that RebuildPackExpandionType is a customization point, it might not be a bad idea to preserve them)?
Alternatively, we could forego calling RebuildPackExpansionType - since OldType is decomposed directly into a PackExpansionType -- NewType could be recomposed directly via Context.getPackExpansionType(NewType, NumExpansions=0)?
Which brings me to - when we create the new pack expansion type, shouldn't the NumExpansions be reset to 0? The fact that we will have a SubstTemplateParameterType replacing the TemplateParameterType within the pattern might influence the answer to that...
Also - we should be able to assert here that *NumExpansions should be one? Can you think of a case that it wouldn't be?