From: Douglas Gregor Date: Wed, 27 May 2009 05:35:12 +0000 (+0000) Subject: Initial stab at a generalized operation for determining the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=815215daf8f642b53a28212313fca7b9f77e5b9d;p=clang Initial stab at a generalized operation for determining the instantiation of a declaration from the template version (or version that lives in a template) and a given set of template arguments. This needs much, much more testing, but it suffices for simple examples like typedef T* iterator; iterator begin(); git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72461 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 25284318a3..3014a8e2ea 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2138,7 +2138,7 @@ public: /// this template instantiation. Sema &SemaRef; - /// \brief A mapping from local variable declarations that occur + /// \brief A mapping from local declarations that occur /// within a template to their instantiations. /// /// This mapping is used during instantiation to keep track of, @@ -2152,7 +2152,7 @@ public: /// 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; + llvm::DenseMap LocalDecls; /// \brief The outer scope, in which contains local variable /// definitions from some other instantiation (that is not @@ -2173,20 +2173,24 @@ public: SemaRef.CurrentInstantiationScope = Outer; } - VarDecl *getInstantiationOf(const VarDecl *Var) { - VarDecl *Result = LocalDecls[Var]; - assert(Result && "Variable was not instantiated in this scope!"); + Decl *getInstantiationOf(const Decl *D) { + Decl *Result = LocalDecls[D]; + assert(Result && "declaration was not instantiated in this scope!"); return Result; } + VarDecl *getInstantiationOf(const VarDecl *Var) { + return cast(getInstantiationOf(cast(Var))); + } + ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { - return cast(getInstantiationOf(cast(Var))); + return cast(getInstantiationOf(cast(Var))); } - void InstantiatedLocal(const VarDecl *Var, VarDecl *VarInst) { - VarDecl *&Stored = LocalDecls[Var]; - assert(!Stored && "Already instantiated this local variable"); - Stored = VarInst; + void InstantiatedLocal(const Decl *D, Decl *Inst) { + Decl *&Stored = LocalDecls[D]; + assert(!Stored && "Already instantiated this local"); + Stored = Inst; } }; @@ -2246,6 +2250,9 @@ public: FunctionDecl *Function); void InstantiateVariableDefinition(VarDecl *Var); + NamedDecl * + InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs); + // Simple function for cloning expressions. template OwningExprResult Clone(T *E) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 86e69997bc..1cc999201b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -406,9 +406,13 @@ InstantiateFunctionNoProtoType(const FunctionNoProtoType *T, QualType TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate TypedefType yet"); - return QualType(); + TypedefDecl *Typedef + = cast_or_null(SemaRef.InstantiateDeclRef(T->getDecl(), + TemplateArgs)); + if (!Typedef) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Typedef); } QualType @@ -435,17 +439,25 @@ TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T, QualType TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate RecordType yet"); - return QualType(); + RecordDecl *Record + = cast_or_null(SemaRef.InstantiateDeclRef(T->getDecl(), + TemplateArgs)); + if (!Record) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Record); } QualType TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate EnumType yet"); - return QualType(); + EnumDecl *Enum + = cast_or_null(SemaRef.InstantiateDeclRef(T->getDecl(), + TemplateArgs)); + if (!Enum) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Enum); } QualType diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 90c86ec57e..e69a1ce644 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -635,3 +635,125 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, void Sema::InstantiateVariableDefinition(VarDecl *Var) { // FIXME: Implement this! } + +static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { + if (D->getKind() != Other->getKind()) + return false; + + if (CXXRecordDecl *Record = dyn_cast(Other)) + return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass()) + == Ctx.getCanonicalDecl(D); + + if (FunctionDecl *Function = dyn_cast(Other)) + return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction()) + == Ctx.getCanonicalDecl(D); + + // FIXME: Need something similar to the above for EnumDecls. + + // FIXME: How can we find instantiations of anonymous unions? + + return D->getDeclName() && isa(Other) && + D->getDeclName() == cast(Other)->getDeclName(); +} + +template +static NamedDecl *findInstantiationOf(ASTContext &Ctx, + NamedDecl *D, + ForwardIterator first, + ForwardIterator last) { + for (; first != last; ++first) + if (isInstantiationOf(Ctx, D, *first)) + return cast(*first); + + return 0; +} + +/// \brief Find the instantiation of the given declaration with the +/// given template arguments. +/// +/// This routine is intended to be used when \p D is a declaration +/// referenced from within a template, that needs to mapped into the +/// corresponding declaration within an instantiation. For example, +/// given: +/// +/// \code +/// template +/// struct X { +/// enum Kind { +/// KnownValue = sizeof(T) +/// }; +/// +/// bool getKind() const { return KnownValue; } +/// }; +/// +/// template struct X; +/// \endcode +/// +/// In the instantiation of X::getKind(), we need to map the +/// EnumConstantDecl for KnownValue (which refers to +/// X::::KnownValue) to its instantiation +/// (X::::KnownValue). InstantiateDeclRef() performs this +/// mapping, given the template arguments 'int'. +NamedDecl * +Sema::InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs) { + DeclContext *ParentDC = D->getDeclContext(); + + if (!ParentDC->isFileContext()) { + NamedDecl *ParentDecl = cast(ParentDC); + ParentDecl = InstantiateDeclRef(ParentDecl, TemplateArgs); + if (!ParentDecl) + return 0; + + ParentDC = cast(ParentDecl); + } + + if (ParentDC->isFunctionOrMethod()) { + // D is a local of some kind. Look into the map of local + // variables to their instantiations. + return cast(CurrentInstantiationScope->getInstantiationOf(D)); + } + + if (ParentDC != D->getDeclContext()) { + // We performed some kind of instantiation in the parent context, + // so now we need to look into the instantiated parent context to + // find the instantiation of the declaration D. + NamedDecl *Result = 0; + if (D->getDeclName()) { + DeclContext::lookup_result Found + = ParentDC->lookup(Context, D->getDeclName()); + Result = findInstantiationOf(Context, D, Found.first, Found.second); + } else { + // Since we don't have a name for the entity we're looking for, + // our only option is to walk through all of the declarations to + // find that name. This will occur in a few cases: + // + // - anonymous struct/union within a template + // - unnamed class/struct/union/enum within a template + // + // FIXME: Find a better way to find these instantiations! + Result = findInstantiationOf(Context, D, + ParentDC->decls_begin(Context), + ParentDC->decls_end(Context)); + } + assert(Result && "Unable to find instantiation of declaration!"); + D = Result; + } + + // D itself might be a class template that we need to instantiate + // with the given template arguments. + if (CXXRecordDecl *Record = dyn_cast(D)) + if (ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate()) { + QualType InjectedClassName + = ClassTemplate->getInjectedClassNameType(Context); + QualType InstantiatedType = InstantiateType(InjectedClassName, + TemplateArgs, + Record->getLocation(), + Record->getDeclName()); + if (InstantiatedType.isNull()) + return 0; + if (const RecordType *RT = InstantiatedType->getAsRecordType()) + D = RT->getDecl(); + } + + return D; +} diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 9dc14d551b..a0fc25de92 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -108,6 +108,7 @@ TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr( Sema::OwningExprResult TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { + // FIXME: Recast this in terms of Sema::InstantiateDeclRef. Decl *D = E->getDecl(); ValueDecl *NewD = 0; if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp index 990c799ee1..1fe85d920c 100644 --- a/test/SemaTemplate/example-dynarray.cpp +++ b/test/SemaTemplate/example-dynarray.cpp @@ -77,16 +77,14 @@ class dynarray { return Start[Idx]; } - // FIXME: use these for begin/end when we can instantiate - // TypedefType nodes. typedef T* iterator; typedef const T* const_iterator; - T* begin() { return Start; } - const T* begin() const { return Start; } + iterator begin() { return Start; } + const_iterator begin() const { return Start; } - T* end() { return Last; } - const T* end() const { return Last; } + iterator end() { return Last; } + const_iterator end() const { return Last; } public: T* Start, *Last, *End; @@ -115,6 +113,9 @@ int main() { for (dynarray::iterator I = di.begin(), IEnd = di.end(); I != IEnd; ++I) assert(*I == I - di.begin()); + for (int I = 0, N = di.size(); I != N; ++I) + assert(di[I] == I); + di.pop_back(); assert(di.size() == 4); di.push_back(4);