summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaTemplate.cpp5
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp48
-rw-r--r--test/CXX/temp/temp.spec/temp.inst/p1.cpp11
-rw-r--r--test/SemaTemplate/instantiate-local-class.cpp96
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([]() {});
+}
+}