Hi rsmith, doug.gregor,
We wouldn't properly save and restore the pending local instantiations
we had built up prior to instantiation of a variable definition. This
would lead to us instantiating too much causing crashes and other
general badness.
Depends on D2236.
Fixes PR14374.
http://llvm-reviews.chandlerc.com/D2238
Files:
include/clang/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.inst/p1.cpp
test/SemaTemplate/instantiate-local-class.cpp
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -6406,6 +6406,24 @@
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
+ class SavePendingLocalImplicitInstantiationsRAII {
+ public:
+ SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) {
+ SavedPendingLocalImplicitInstantiations.swap(
+ S.PendingLocalImplicitInstantiations);
+ }
+
+ ~SavePendingLocalImplicitInstantiationsRAII() {
+ SavedPendingLocalImplicitInstantiations.swap(
+ S.PendingLocalImplicitInstantiations);
+ }
+
+ private:
+ Sema &S;
+ std::deque<PendingImplicitInstantiation>
+ SavedPendingLocalImplicitInstantiations;
+ };
+
void PerformPendingInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -6270,7 +6270,10 @@
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) {
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2457,6 +2457,11 @@
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) {
@@ -2497,6 +2502,9 @@
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)) {
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ 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())
@@ -657,19 +668,17 @@
}
}
- 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()))
+ if (isDeclWithinFunction(D) ? D == Def : (Def && !Enum->isScoped())) {
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
InstantiateEnumDefinition(Enum, Def);
+ }
return Enum;
}
@@ -724,7 +733,7 @@
LastEnumConst = EnumConst;
if (Pattern->getDeclContext()->isFunctionOrMethod() &&
- !Enum->isScoped()) {
+ !Enum->isScoped() && !Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum
// constant as a local.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
@@ -1120,13 +1129,24 @@
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);
+
+ 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;
}
@@ -3202,10 +3222,8 @@
// while we're still within our own instantiation context.
SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
- std::deque<PendingImplicitInstantiation>
- SavedPendingLocalImplicitInstantiations;
- SavedPendingLocalImplicitInstantiations.swap(
- PendingLocalImplicitInstantiations);
+ SavePendingLocalImplicitInstantiationsRAII
+ SavedPendingLocalImplicitInstantiations(*this);
if (Recursive) {
VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
@@ -3286,8 +3304,6 @@
"PendingInstantiations should be empty before it is discarded.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
- SavedPendingLocalImplicitInstantiations.swap(
- PendingLocalImplicitInstantiations);
}
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
@@ -3705,6 +3721,8 @@
// while we're still within our own instantiation context.
SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ SavePendingLocalImplicitInstantiationsRAII
+ SavedPendingLocalImplicitInstantiations(*this);
if (Recursive) {
VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
Index: test/CXX/temp/temp.spec/temp.inst/p1.cpp
===================================================================
--- test/CXX/temp/temp.spec/temp.inst/p1.cpp
+++ test/CXX/temp/temp.spec/temp.inst/p1.cpp
@@ -33,24 +33,23 @@
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.
+ // CWG1484 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}}
}
Index: test/SemaTemplate/instantiate-local-class.cpp
===================================================================
--- test/SemaTemplate/instantiate-local-class.cpp
+++ 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,117 @@
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([]() {});
+}
+}
+
+namespace PR14373 {
+ struct function {
+ template <typename _Functor> function(_Functor __f) { __f(); }
+ };
+ template <typename Func> function exec_func(Func f) {
+ struct functor {
+ functor(Func f) : func(f) {}
+ void operator()() const { func(); }
+ Func func;
+ };
+ return functor(f);
+ }
+ struct Type {
+ void operator()() const {}
+ };
+ int call() {
+ exec_func(Type());
+ }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits