[PATCH] Sema: Instantiate local class and their members appropriately
David Majnemer
david.majnemer at gmail.com
Wed Nov 20 16:08:51 PST 2013
Hi rsmith, doug.gregor,
We would fail to instantiate them when the surrounding function was
instantiated. Instantiate the class and add it's members to the list of
pending instantiations, they should be resolved when we are finished
with the function's body.
http://llvm-reviews.chandlerc.com/D2236
Files:
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.inst/p1.cpp
test/SemaCXX/local-classes.cpp
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) {
@@ -2482,7 +2487,8 @@
if (Function->isDefined())
continue;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
+ if (TSK == TSK_ExplicitInstantiationDefinition ||
+ TSK == TSK_ImplicitInstantiation) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
@@ -2494,7 +2500,11 @@
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- InstantiateFunctionDefinition(PointOfInstantiation, Function);
+ if (TSK == TSK_ImplicitInstantiation)
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
+ else
+ InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else {
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
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,7 +668,7 @@
}
}
- if (D->getDeclContext()->isFunctionOrMethod())
+ if (isDeclWithinFunction(D))
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
// C++11 [temp.inst]p1: The implicit instantiation of a class template
@@ -667,8 +678,7 @@
// 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()))
InstantiateEnumDefinition(Enum, Def);
return Enum;
@@ -723,8 +733,7 @@
Enumerators.push_back(EnumConst);
LastEnumConst = EnumConst;
- if (Pattern->getDeclContext()->isFunctionOrMethod() &&
- !Enum->isScoped()) {
+ if (isDeclWithinFunction(Pattern) && !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,26 @@
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 (CXXRecordDecl *Def = D->getDefinition()) {
+ if (Def->isLocalClass()) {
+ if (SemaRef.InstantiateClass(D->getLocation(), Record, Def, TemplateArgs,
+ TSK_ImplicitInstantiation,
+ /*Complain=*/true)) {
+ llvm_unreachable("InstantiateClass shouldn't fail here!");
+ } else {
+ SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+ TSK_ImplicitInstantiation);
+ }
+ }
+ }
return Record;
}
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
@@ -39,18 +39,18 @@
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/SemaCXX/local-classes.cpp
===================================================================
--- test/SemaCXX/local-classes.cpp
+++ test/SemaCXX/local-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// expected-no-diagnostics
namespace PR6382 {
@@ -40,3 +40,11 @@
};
}
}
+
+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>(); }
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2236.1.patch
Type: text/x-patch
Size: 6717 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131120/f0ed1d20/attachment.bin>
More information about the cfe-commits
mailing list