From: Douglas Gregor Date: Sat, 16 Jan 2010 22:29:39 +0000 (+0000) Subject: Introduce a second queue of "local" pending implicit instantiation, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=60406bede202b66ebdd98cac0c38d20f9698aeca;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93666 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c14ce293ac..02e3a7a93d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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 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 PendingLocalImplicitInstantiations; + + void PerformPendingImplicitInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0b97d761b6..31ec778390 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(Function->getDeclContext()) && + cast(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 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e6be5389cd..98619f3a16 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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(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(Inst.first)) { diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp index eaaae9b6ee..768eb2170a 100644 --- a/test/SemaTemplate/instantiate-local-class.cpp +++ b/test/SemaTemplate/instantiate-local-class.cpp @@ -16,8 +16,11 @@ namespace PR5764 { class X { template void Bar() { + typedef T ValueType; class Y { - Y() {} + Y() { V = ValueType(); } + + ValueType V; }; Y y;