From: Richard Smith Date: Mon, 9 Jul 2012 03:07:20 +0000 (+0000) Subject: PR13136: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6098381c29c2693832aa81ef046cf21a49729436;p=clang PR13136: * When substituting a reference to a non-type template parameter pack where the corresponding argument is a pack expansion, transform into an expression which contains an unexpanded parameter pack rather than into an expression which contains a pack expansion. This causes the SubstNonTypeTemplateParmExpr to be inside the PackExpansionExpr, rather than outside, so the expression still looks like a pack expansion and can be deduced. * Teach MarkUsedTemplateParameters that we can deduce a reference to a template parameter if it's wrapped in a SubstNonTypeTemplateParmExpr (such nodes are added during alias template substitution). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159922 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b8ec59ee1d..60f5bc196e 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -4166,9 +4166,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (const PackExpansionExpr *Expansion = dyn_cast(E)) E = Expansion->getPattern(); - // Skip through any implicit casts we added while type-checking. - while (const ImplicitCastExpr *ICE = dyn_cast(E)) - E = ICE->getSubExpr(); + // Skip through any implicit casts we added while type-checking, and any + // substitutions performed by template alias expansion. + while (1) { + if (const ImplicitCastExpr *ICE = dyn_cast(E)) + E = ICE->getSubExpr(); + else if (const SubstNonTypeTemplateParmExpr *Subst = + dyn_cast(E)) + E = Subst->getReplacement(); + else + break; + } // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7416d12301..239a0d73eb 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -851,7 +851,7 @@ namespace { private: ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, SourceLocation loc, - const TemplateArgument &arg); + TemplateArgument arg); }; } @@ -1140,10 +1140,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( NonTypeTemplateParmDecl *parm, SourceLocation loc, - const TemplateArgument &arg) { + TemplateArgument arg) { ExprResult result; QualType type; + // If the argument is a pack expansion, the parameter must actually be a + // parameter pack, and we should substitute the pattern itself, producing + // an expression which contains an unexpanded parameter pack. + if (arg.isPackExpansion()) { + assert(parm->isParameterPack() && "pack expansion for non-pack"); + arg = arg.getPackExpansionPattern(); + } + // The template argument itself might be an expression, in which // case we just return that expression. if (arg.getKind() == TemplateArgument::Expression) { diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp index a074bc4e1e..cd796b8603 100644 --- a/test/SemaTemplate/alias-templates.cpp +++ b/test/SemaTemplate/alias-templates.cpp @@ -109,3 +109,22 @@ namespace PR13243 { template void f(X, Ci) {} template void f(X, C<0>); } + +namespace PR13136 { + template + struct NumberTuple { }; + + template + using MyNumberTuple = NumberTuple; + + template + void foo(U&&, MyNumberTuple); + + template + void bar(U&&, NumberTuple); + + int main() { + foo(1, NumberTuple()); + bar(1, NumberTuple()); + } +}