From 68eea507fa46d2697e51d552efba2341060c0fb3 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 16 Jul 2012 00:20:35 +0000 Subject: [PATCH] Related to PR11848 and core-21989: switch ContainsUnexpandedParameterPack from being a property of a canonical type to being a property of the fully-sugared type. This should only make a difference in the case where an alias template ignores one of its parameters, and that parameter is an unexpanded parameter pack. llvm-svn: 160244 --- clang/lib/AST/ASTContext.cpp | 13 ++++-- clang/lib/AST/Type.cpp | 7 +-- clang/test/SemaTemplate/alias-templates.cpp | 48 ++++++++++++++++++--- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b0351d69adb5..c83e70a72bf4 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4fef11f2a8b0..eacf505442cc 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/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/clang/test/SemaTemplate/alias-templates.cpp b/clang/test/SemaTemplate/alias-templates.cpp index cd796b8603d2..a3d66ae63b9b 100644 --- a/clang/test/SemaTemplate/alias-templates.cpp +++ b/clang/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; } }