diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b0351d69ad..c83e70a72b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2892,10 +2892,17 @@ QualType ASTContext::getPackExpansionType(QualType Pattern, QualType Canon; if (!Pattern.isCanonical()) { - Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions); + Canon = getCanonicalType(Pattern); + // The canonical type might not contain an unexpanded parameter pack, if it + // contains an alias template specialization which ignores one of its + // parameters. + if (Canon->containsUnexpandedParameterPack()) { + Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions); - // Find the insert position again. - PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + // Find the insert position again, in case we inserted an element into + // PackExpansionTypes and invalidated our insert position. + PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + } } T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4fef11f2a8..eacf505442 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1862,8 +1862,7 @@ TemplateSpecializationType(TemplateName T, Canon.isNull()? T.isDependent() : Canon->isInstantiationDependentType(), false, - Canon.isNull()? T.containsUnexpandedParameterPack() - : Canon->containsUnexpandedParameterPack()), + T.containsUnexpandedParameterPack()), Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) { assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); @@ -1888,6 +1887,8 @@ TemplateSpecializationType(TemplateName T, // arguments is. Given: // template using U = int; // U is always non-dependent, irrespective of the type T. + // However, U contains an unexpanded parameter pack, even though + // its expansion (and thus its desugared type) doesn't. if (Canon.isNull() && Args[Arg].isDependent()) setDependent(); else if (Args[Arg].isInstantiationDependent()) @@ -1896,7 +1897,7 @@ TemplateSpecializationType(TemplateName T, if (Args[Arg].getKind() == TemplateArgument::Type && Args[Arg].getAsType()->isVariablyModifiedType()) setVariablyModified(); - if (Canon.isNull() && Args[Arg].containsUnexpandedParameterPack()) + if (Args[Arg].containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp index cd796b8603..a3d66ae63b 100644 --- a/test/SemaTemplate/alias-templates.cpp +++ b/test/SemaTemplate/alias-templates.cpp @@ -73,19 +73,38 @@ namespace PR11848 { template using U = int; template - void f(U i, U ...is) { // expected-error {{type 'U' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}} - return i + f(is...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}} + void f1(U i, U ...is) { // expected-note 2{{couldn't infer template argument 'T'}} + return i + f1(is...); + } + + // FIXME: This note is technically correct, but could be better. We + // should really say that we couldn't infer template argument 'Ts'. + template + void f2(U ...is) { } // expected-note {{requires 0 arguments, but 1 was provided}} + + template struct type_tuple {}; + template + void f3(type_tuple, U ...is) {} // expected-note {{requires 4 arguments, but 3 were provided}} + + void g() { + f1(U()); // expected-error {{no match}} + f1(1, 2, 3, 4, 5); // expected-error {{no match}} + f2(); // ok + f2(1); // expected-error {{no match}} + f3(type_tuple<>()); + f3(type_tuple(), 1, 2); // expected-error {{no match}} + f3(type_tuple(), 1, 2, 3); } template struct S { - S(U...ts); // expected-error {{does not contain any unexpanded parameter packs}} + S(U...ts); }; template struct Hidden1 { template - Hidden1(typename T::template U ...ts); // expected-error{{type 'typename Hide::U' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}} + Hidden1(typename T::template U ...ts); }; template @@ -97,10 +116,28 @@ namespace PR11848 { template using U = int; }; - Hidden1 h1; // expected-note{{in instantiation of template class 'PR11848::Hidden1' requested here}} + Hidden1 h1; Hidden2 h2(1, 2); } +namespace Core22036 { + struct X {}; + void h(...); + template using Y = X; + template struct S { + void f1(Y a) { h(g(a)); } // expected-error {{undeclared identifier 'g'}} + // FIXME: We should reject this too: 'as' has non-dependent type 'X', so + // ADL should be performed at the point of definition of the + // template. + void f2(Y...as) { h(g(as)...); } + }; + int g(X); + void test() { + S().f1({}); + S().f2({}); + } +} + namespace PR13243 { template struct X {}; template struct C {}; @@ -126,5 +163,6 @@ namespace PR13136 { int main() { foo(1, NumberTuple()); bar(1, NumberTuple()); + return 0; } }