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
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index b931cf8..411d5a1 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -182,7 +182,8 @@
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 6cc8a99..d4c03a1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2092,6 +2092,73 @@
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<typename T> T add(T x, T y) { return x + y; }
+ /// \endcode
+ ///
+ /// when we instantiate add<int>, we will introduce a mapping from
+ /// the ParmVarDecl for 'x' that occurs in the template to the
+ /// instantiated ParmVarDecl for 'x'.
+ llvm::DenseMap<VarDecl *, VarDecl *> 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<ParmVarDecl>(getInstantiationOf(cast<VarDecl>(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 6ae6b22..19aaafb 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -279,6 +279,8 @@
if (D->getKind() != Decl::CXXMethod)
return 0;
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
@@ -320,6 +322,8 @@
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
@@ -363,6 +367,8 @@
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
@@ -391,6 +397,8 @@
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
@@ -452,6 +460,7 @@
// 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 89d88ff..d7b0854 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -85,6 +85,15 @@
*Arg.getAsIntegral(),
T,
E->getSourceRange().getBegin()));
+ } else if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(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 ea1e0af..1832fd4 100644
--- a/test/SemaTemplate/instantiate-expr-2.cpp
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -120,8 +120,6 @@
typedef Cond<true, int, double>::Type Type;
}
-#if 0
-// FIXME: Unable to handle general declaration references at this point.
template<typename T, unsigned long N> struct IntegralConstant { };
template<typename T>
@@ -130,6 +128,5 @@
};
void test_X0(X0<int> x, IntegralConstant<int, sizeof(int)> ic) {
- x.f(ic);
+ x.f(5, ic);
}
-#endif