diff options
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 48 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.inst/p1.cpp | 11 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-local-class.cpp | 96 |
5 files changed, 147 insertions, 21 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 63d8d8db26..e995ae1c36 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6265,7 +6265,10 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, switch (NewTSK) { case TSK_Undeclared: case TSK_ImplicitInstantiation: - llvm_unreachable("Don't check implicit instantiations here"); + assert( + (PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) && + "previous declaration must be implicit!"); + return false; case TSK_ExplicitSpecialization: switch (PrevTSK) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 40e020dc07..7dc8d2b195 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2456,6 +2456,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK) { + assert( + (TSK == TSK_ExplicitInstantiationDefinition || + TSK == TSK_ExplicitInstantiationDeclaration || + (TSK == TSK_ImplicitInstantiation && Instantiation->isLocalClass())) && + "Unexpected template specialization kind!"); for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { @@ -2496,6 +2501,9 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, InstantiateFunctionDefinition(PointOfInstantiation, Function); } else { Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + if (TSK == TSK_ImplicitInstantiation) + PendingLocalImplicitInstantiations.push_back( + std::make_pair(Function, PointOfInstantiation)); } } } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index a0af032953..3e19249058 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -25,6 +25,17 @@ using namespace clang; +static bool isDeclWithinFunction(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + if (DC->isFunctionOrMethod()) + return true; + + if (DC->isRecord()) + return cast<CXXRecordDecl>(DC)->isLocalClass(); + + return false; +} + bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, DeclaratorDecl *NewDecl) { if (!OldDecl->getQualifierLoc()) @@ -655,19 +666,17 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } } - if (D->getDeclContext()->isFunctionOrMethod()) - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); - // C++11 [temp.inst]p1: The implicit instantiation of a class template // specialization causes the implicit instantiation of the declarations, but // not the definitions of scoped member enumerations. - // FIXME: There appears to be no wording for what happens for an enum defined - // within a block scope, but we treat that much like a member template. Only - // instantiate the definition when visiting the definition in that case, since - // we will visit all redeclarations. - if (!Enum->isScoped() && Def && - (!D->getDeclContext()->isFunctionOrMethod() || D->isCompleteDefinition())) + // + // DR1484 clarifies that enumeration definitions inside of a template + // declaration aren't considered entities that can be separately instantiated + // from the rest of the entity they are declared inside of. + if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) { + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); InstantiateEnumDefinition(Enum, Def); + } return Enum; } @@ -1118,13 +1127,26 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Record->setObjectOfFriendDecl(); // Make sure that anonymous structs and unions are recorded. - if (D->isAnonymousStructOrUnion()) { + if (D->isAnonymousStructOrUnion()) Record->setAnonymousStructOrUnion(true); - if (Record->getDeclContext()->getRedeclContext()->isFunctionOrMethod()) - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record); - } + + if (D->isLocalClass()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record); Owner->addDecl(Record); + + // DR1484 clarifies that the members of a local class are instantiated as part + // of the instantiation of their enclosing entity. + if (D->isCompleteDefinition() && D->isLocalClass()) { + if (SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs, + TSK_ImplicitInstantiation, + /*Complain=*/true)) { + llvm_unreachable("InstantiateClass shouldn't fail here!"); + } else { + SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs, + TSK_ImplicitInstantiation); + } + } return Record; } diff --git a/test/CXX/temp/temp.spec/temp.inst/p1.cpp b/test/CXX/temp/temp.spec/temp.inst/p1.cpp index 8684fc4dab..adf812b714 100644 --- a/test/CXX/temp/temp.spec/temp.inst/p1.cpp +++ b/test/CXX/temp/temp.spec/temp.inst/p1.cpp @@ -33,24 +33,23 @@ namespace ScopedEnum { ScopedEnum1<double>::E e1; // ok ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}} - // The behavior for enums defined within function templates is not clearly - // specified by the standard. We follow the rules for enums defined within - // class templates. + // DR1484 specifies that enumerations cannot be separately instantiated, + // they will be instantiated with the rest of the template declaration. template<typename T> int f() { enum class E { - e = T::error + e = T::error // expected-error {{has no members}} }; return (int)E(); } - int test1 = f<int>(); + int test1 = f<int>(); // expected-note {{here}} template<typename T> int g() { enum class E { e = T::error // expected-error {{has no members}} }; - return E::e; // expected-note {{here}} + return E::e; } int test2 = g<int>(); // expected-note {{here}} } diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp index c151fbb9a5..2b5db0fda3 100644 --- a/test/SemaTemplate/instantiate-local-class.cpp +++ b/test/SemaTemplate/instantiate-local-class.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify %s +// RUN: %clang_cc1 -verify -std=c++11 %s // expected-no-diagnostics template<typename T> void f0() { @@ -66,3 +66,97 @@ namespace PR8801 { template void foo<Y>(); } + +namespace TemplatePacksAndLambdas { + template <typename ...T> int g(T...); + struct S { + template <typename ...T> static void f(int f = g([]{ static T t; return ++t; }()...)) {} + }; + void h() { S::f<int, int, int>(); } +} + +namespace PR9685 { + template <class Thing> void forEach(Thing t) { t.func(); } + + template <typename T> void doIt() { + struct Functor { + void func() { (void)i; } + int i; + }; + + forEach(Functor()); + } + + void call() { + doIt<int>(); + } +} + +namespace PR12702 { + struct S { + template <typename F> bool apply(F f) { return f(); } + }; + + template <typename> struct T { + void foo() { + struct F { + int x; + + bool operator()() { return x == 0; } + }; + + S().apply(F()); + } + }; + + void call() { T<int>().foo(); } +} + +namespace PR17139 { + template <class T> void foo(const T &t) { t.foo(); } + + template <class F> void bar(F *f) { + struct B { + F *fn; + void foo() const { fn(); } + } b = { f }; + foo(b); + } + + void go() {} + + void test() { bar(go); } +} + +namespace PR17740 { +class C { +public: + template <typename T> static void foo(T function); + template <typename T> static void bar(T function); + template <typename T> static void func(T function); +}; + +template <typename T> void C::foo(T function) { function(); } + +template <typename T> void C::bar(T function) { + foo([&function]() { function(); }); +} + +template <typename T> void C::func(T function) { + struct Struct { + T mFunction; + + Struct(T function) : mFunction(function) {}; + + void operator()() { + mFunction(); + }; + }; + + bar(Struct(function)); +} + +void call() { + C::func([]() {}); +} +} |