diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-05-27 05:35:12 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-05-27 05:35:12 +0000 |
commit | 815215daf8f642b53a28212313fca7b9f77e5b9d (patch) | |
tree | 69e5ffd49e965203e38e6dfa545c6cb08f300fb9 /lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | 7ff69269cf13583a981b265d4edee689feb4a830 (diff) |
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
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 122 |
1 files changed, 122 insertions, 0 deletions
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<CXXRecordDecl>(Other)) + return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass()) + == Ctx.getCanonicalDecl(D); + + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(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<NamedDecl>(Other) && + D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); +} + +template<typename ForwardIterator> +static NamedDecl *findInstantiationOf(ASTContext &Ctx, + NamedDecl *D, + ForwardIterator first, + ForwardIterator last) { + for (; first != last; ++first) + if (isInstantiationOf(Ctx, D, *first)) + return cast<NamedDecl>(*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<typename T> +/// struct X { +/// enum Kind { +/// KnownValue = sizeof(T) +/// }; +/// +/// bool getKind() const { return KnownValue; } +/// }; +/// +/// template struct X<int>; +/// \endcode +/// +/// In the instantiation of X<int>::getKind(), we need to map the +/// EnumConstantDecl for KnownValue (which refers to +/// X<T>::<Kind>::KnownValue) to its instantiation +/// (X<int>::<Kind>::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<NamedDecl>(ParentDC); + ParentDecl = InstantiateDeclRef(ParentDecl, TemplateArgs); + if (!ParentDecl) + return 0; + + ParentDC = cast<DeclContext>(ParentDecl); + } + + if (ParentDC->isFunctionOrMethod()) { + // D is a local of some kind. Look into the map of local + // variables to their instantiations. + return cast<NamedDecl>(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<CXXRecordDecl>(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; +} |