diff options
-rw-r--r-- | include/clang/AST/Decl.h | 4 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 150 |
3 files changed, 114 insertions, 50 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 197b9dbbc4..afee0f15ca 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1379,6 +1379,10 @@ class EnumDecl : public TagDecl { IntegerType = QualType(); } public: + EnumDecl *getCanonicalDecl() { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + static EnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL, EnumDecl *PrevDecl); diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 0c7fc6ceb2..a6d32476a7 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -405,8 +405,12 @@ public: /// reverse_base_class_iterator = Iterator that traverses the base classes /// of a class in reverse order. - typedef std::reverse_iterator<base_class_const_iterator> - reverse_base_class_const_iterator; + typedef std::reverse_iterator<base_class_const_iterator> + reverse_base_class_const_iterator; + + virtual CXXRecordDecl *getCanonicalDecl() { + return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); + } static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -712,7 +716,7 @@ public: return dyn_cast<FunctionDecl>(getDeclContext()); } - + /// viewInheritance - Renders and displays an inheritance diagram /// for this C++ class and all of its base classes (transitively) using /// GraphViz. diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ba5c786366..6c1f0115b6 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1166,38 +1166,94 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, NewInits.data(), NewInits.size()); } +// TODO: this could be templated if the various decl types used the +// same method name. +static bool isInstantiationOf(ClassTemplateDecl *Pattern, + ClassTemplateDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberTemplate(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(CXXRecordDecl *Pattern, + CXXRecordDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberClass(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(FunctionDecl *Pattern, + FunctionDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberFunction(); + } while (Instance); + + return false; +} + +static bool isInstantiationOf(EnumDecl *Pattern, + EnumDecl *Instance) { + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromMemberEnum(); + } while (Instance); + + return false; +} + +static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, + VarDecl *Instance) { + assert(Instance->isStaticDataMember()); + + Pattern = Pattern->getCanonicalDecl(); + + do { + Instance = Instance->getCanonicalDecl(); + if (Pattern == Instance) return true; + Instance = Instance->getInstantiatedFromStaticDataMember(); + } while (Instance); + + return false; +} + static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) return false; - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other)) { - if (CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass()) - return Pattern->getCanonicalDecl() == D->getCanonicalDecl(); - else - return false; - } + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other)) + return isInstantiationOf(cast<CXXRecordDecl>(D), Record); - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other)) { - if (FunctionDecl *Pattern = Function->getInstantiatedFromMemberFunction()) - return Pattern->getCanonicalDecl() == D->getCanonicalDecl(); - else - return false; - } + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other)) + return isInstantiationOf(cast<FunctionDecl>(D), Function); - if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other)) { - if (EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum()) - return Pattern->getCanonicalDecl() == D->getCanonicalDecl(); - else - return false; - } + if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other)) + return isInstantiationOf(cast<EnumDecl>(D), Enum); if (VarDecl *Var = dyn_cast<VarDecl>(Other)) - if (Var->isStaticDataMember()) { - if (VarDecl *Pattern = Var->getInstantiatedFromStaticDataMember()) - return Pattern->getCanonicalDecl() == D->getCanonicalDecl(); - else - return false; - } + if (Var->isStaticDataMember()) + return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var); + + if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other)) + return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp); // FIXME: How can we find instantiations of anonymous unions? @@ -1262,6 +1318,28 @@ NamedDecl * Sema::FindInstantiatedDecl(NamedDecl *D) { return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); } + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) + if (ClassTemplateDecl *ClassTemplate + = Record->getDescribedClassTemplate()) { + // When the declaration D was parsed, it referred to the current + // instantiation. Therefore, look through the current context, + // which contains actual instantiations, to find the + // instantiation of the "current instantiation" that D refers + // to. Alternatively, we could just instantiate the + // injected-class-name with the current template arguments, but + // such an instantiation is far more expensive. + for (DeclContext *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) + if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate())) + return Spec; + } + + assert(false && + "Unable to find declaration for the current instantiation"); + } + ParentDC = FindInstantiatedContext(ParentDC); if (!ParentDC) return 0; @@ -1286,33 +1364,11 @@ NamedDecl * Sema::FindInstantiatedDecl(NamedDecl *D) { ParentDC->decls_begin(), ParentDC->decls_end()); } + assert(Result && "Unable to find instantiation of declaration!"); D = Result; } - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) - if (ClassTemplateDecl *ClassTemplate - = Record->getDescribedClassTemplate()) { - // When the declaration D was parsed, it referred to the current - // instantiation. Therefore, look through the current context, - // which contains actual instantiations, to find the - // instantiation of the "current instantiation" that D refers - // to. Alternatively, we could just instantiate the - // injected-class-name with the current template arguments, but - // such an instantiation is far more expensive. - for (DeclContext *DC = CurContext; !DC->isFileContext(); - DC = DC->getParent()) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) - if (Spec->getSpecializedTemplate()->getCanonicalDecl() - == ClassTemplate->getCanonicalDecl()) - return Spec; - } - - assert(false && - "Unable to find declaration for the current instantiation"); - } - return D; } |