aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateInstantiateDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-05-27 05:35:12 +0000
committerDouglas Gregor <dgregor@apple.com>2009-05-27 05:35:12 +0000
commit815215daf8f642b53a28212313fca7b9f77e5b9d (patch)
tree69e5ffd49e965203e38e6dfa545c6cb08f300fb9 /lib/Sema/SemaTemplateInstantiateDecl.cpp
parent7ff69269cf13583a981b265d4edee689feb4a830 (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.cpp122
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;
+}