Introduce a second queue of "local" pending implicit instantiation,

which are instantiations of the member functions of local
classes. These implicit instantiations have to occur at the same time
as---and in the same local instantiation scope as---the enclosing
function, since the member functions of the local class can refer to
locals within the enclosing function. This should really, really fix PR5764.

llvm-svn: 93666
This commit is contained in:
Douglas Gregor
2010-01-16 22:29:39 +00:00
parent 520442b32c
commit 7f792cf329
4 changed files with 61 additions and 11 deletions

View File

@@ -3165,13 +3165,17 @@ public:
/// relevant to this particular scope).
LocalInstantiationScope *Outer;
/// \brief Whether we have already exited this scope.
bool Exited;
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
Exited(false) {
if (!CombineWithOuterScope)
SemaRef.CurrentInstantiationScope = this;
else
@@ -3180,7 +3184,15 @@ public:
}
~LocalInstantiationScope() {
if (!Exited)
SemaRef.CurrentInstantiationScope = Outer;
}
/// \brief Exit this local instantiation scope early.
void Exit() {
SemaRef.CurrentInstantiationScope = Outer;
LocalDecls.clear();
Exited = true;
}
Decl *getInstantiationOf(const Decl *D) {
@@ -3227,7 +3239,16 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations;
void PerformPendingImplicitInstantiations();
/// \brief The queue of implicit template instantiations that are required
/// and must be performed within the current local scope.
///
/// This queue is only used for member functions of local classes in
/// templates, which must be instantiated in the same scope as their
/// enclosing function, so that they can reference function-local
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
void PerformPendingImplicitInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,

View File

@@ -7215,8 +7215,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
AlreadyInstantiated = true;
}
if (!AlreadyInstantiated)
PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
if (!AlreadyInstantiated) {
if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
else
PendingImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
}
}
// FIXME: keep track of references to static functions

View File

@@ -1653,8 +1653,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
// recorded.
LocalInstantiationScope Scope(*this);
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
// scope (of the enclosing function).
bool MergeWithParentScope = false;
if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext()))
MergeWithParentScope = Rec->isLocalClass();
LocalInstantiationScope Scope(*this, MergeWithParentScope);
// Introduce the instantiated function parameters into the local
// instantiation scope.
@@ -1691,6 +1697,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
// This class may have local implicit instantiations that need to be
// instantiation within this scope.
PerformPendingImplicitInstantiations(/*LocalOnly=*/true);
Scope.Exit();
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
@@ -2223,10 +2234,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingImplicitInstantiations() {
while (!PendingImplicitInstantiations.empty()) {
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingImplicitInstantiations.empty())) {
PendingImplicitInstantiation Inst;
if (PendingLocalImplicitInstantiations.empty()) {
Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
} else {
Inst = PendingLocalImplicitInstantiations.front();
PendingLocalImplicitInstantiations.pop_front();
}
// Instantiate function definitions
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {

View File

@@ -16,8 +16,11 @@ namespace PR5764 {
class X {
template <typename T>
void Bar() {
typedef T ValueType;
class Y {
Y() {}
Y() { V = ValueType(); }
ValueType V;
};
Y y;