From 48dd19b19ddb9e105f8cf0bf6f0732ca4e6a385b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 14 May 2009 21:44:34 +0000 Subject: [PATCH] Introduce a stack of instantiation scopes that are used to store the mapping from variable declarations that occur within templates to their instantiated counterparts git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71799 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.cpp | 3 +- lib/Sema/Sema.h | 67 ++++++++++++++++++++++++ lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 ++++ lib/Sema/SemaTemplateInstantiateExpr.cpp | 9 ++++ test/SemaTemplate/instantiate-expr-2.cpp | 5 +- 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index b931cf8967..411d5a1677 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -182,7 +182,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExternalSource(0), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), - CompleteTranslationUnit(CompleteTranslationUnit) { + CompleteTranslationUnit(CompleteTranslationUnit), + CurrentInstantiationScope(0) { StdNamespace = 0; TUScope = 0; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6cc8a99f8e..d4c03a12a8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2092,6 +2092,73 @@ public: void PrintInstantiationStack(); + /// \brief A stack-allocated class that identifies which local + /// variable declaration instantiations are present in this scope. + /// + /// A new instance of this class type will be created whenever we + /// instantiate a new function declaration, which will have its own + /// set of parameter declarations. + class LocalInstantiationScope { + /// \brief Reference to the semantic analysis that is performing + /// this template instantiation. + Sema &SemaRef; + + /// \brief A mapping from local variable declarations that occur + /// within a template to their instantiations. + /// + /// This mapping is used during instantiation to keep track of, + /// e.g., function parameter and variable declarations. For example, + /// given: + /// + /// \code + /// template T add(T x, T y) { return x + y; } + /// \endcode + /// + /// when we instantiate add, we will introduce a mapping from + /// the ParmVarDecl for 'x' that occurs in the template to the + /// instantiated ParmVarDecl for 'x'. + llvm::DenseMap LocalDecls; + + /// \brief The outer scope, in which contains local variable + /// definitions from some other instantiation (that is not + /// relevant to this particular scope). + LocalInstantiationScope *Outer; + + // This class is non-copyable + LocalInstantiationScope(const LocalInstantiationScope &); + LocalInstantiationScope &operator=(const LocalInstantiationScope &); + + public: + LocalInstantiationScope(Sema &SemaRef) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + SemaRef.CurrentInstantiationScope = this; + } + + ~LocalInstantiationScope() { + SemaRef.CurrentInstantiationScope = Outer; + } + + VarDecl *getInstantiationOf(VarDecl *Var) { + VarDecl *Result = LocalDecls[Var]; + assert(Result && "Variable was not instantiated in this scope!"); + return Result; + } + + ParmVarDecl *getInstantiationOf(ParmVarDecl *Var) { + return cast(getInstantiationOf(cast(Var))); + } + + void InstantiatedLocal(VarDecl *Var, VarDecl *VarInst) { + VarDecl *&Stored = LocalDecls[Var]; + assert(!Stored && "Already instantiated this local variable"); + Stored = VarInst; + } + }; + + /// \brief The current instantiation scope used to store local + /// variables. + LocalInstantiationScope *CurrentInstantiationScope; + QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6ae6b2240b..19aaafbcc6 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -279,6 +279,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { if (D->getKind() != Decl::CXXMethod) return 0; + Sema::LocalInstantiationScope Scope(SemaRef); + llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) @@ -320,6 +322,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { } Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) @@ -363,6 +367,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { } Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) @@ -391,6 +397,8 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { } Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) @@ -452,6 +460,7 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { // Note: we don't try to instantiate function parameters until after // we've instantiated the function's type. Therefore, we don't have // to check for 'void' parameter types here. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); return Param; } diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 89d88ff76e..d7b0854997 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -85,6 +85,15 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { *Arg.getAsIntegral(), T, E->getSourceRange().getBegin())); + } else if (ParmVarDecl *Parm = dyn_cast(D)) { + ParmVarDecl *ParmInst + = SemaRef.CurrentInstantiationScope->getInstantiationOf(Parm); + QualType T = ParmInst->getType(); + return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(ParmInst, + T.getNonReferenceType(), + E->getLocation(), + T->isDependentType(), + T->isDependentType())); } else assert(false && "Can't handle arbitrary declaration references"); diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index ea1e0af21a..1832fd4ab7 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -120,8 +120,6 @@ namespace N7 { typedef Cond::Type Type; } -#if 0 -// FIXME: Unable to handle general declaration references at this point. template struct IntegralConstant { }; template @@ -130,6 +128,5 @@ struct X0 { }; void test_X0(X0 x, IntegralConstant ic) { - x.f(ic); + x.f(5, ic); } -#endif -- 2.40.0