diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 165 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 2 |
2 files changed, 130 insertions, 37 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f812244ed3c..7dfcdeb8c4f 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -71,6 +71,25 @@ namespace clang { + template <class T> + SmallVector<Decl*, 2> + getCanonicalForwardRedeclChain(Redeclarable<T>* D) { + SmallVector<Decl*, 2> Redecls; + for (auto *R : D->getFirstDecl()->redecls()) { + if (R != D->getFirstDecl()) + Redecls.push_back(R); + } + Redecls.push_back(D->getFirstDecl()); + std::reverse(Redecls.begin(), Redecls.end()); + return Redecls; + } + + SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D) { + // Currently only FunctionDecl is supported + auto FD = cast<FunctionDecl>(D); + return getCanonicalForwardRedeclChain<FunctionDecl>(FD); + } + class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>, public DeclVisitor<ASTNodeImporter, Decl *>, public StmtVisitor<ASTNodeImporter, Stmt *> { @@ -195,6 +214,12 @@ namespace clang { const InContainerTy &Container, TemplateArgumentListInfo &Result); + using TemplateArgsTy = SmallVector<TemplateArgument, 8>; + using OptionalTemplateArgsTy = Optional<TemplateArgsTy>; + std::tuple<FunctionTemplateDecl *, OptionalTemplateArgsTy> + ImportFunctionTemplateWithTemplateArgsFromSpecialization( + FunctionDecl *FromFD); + bool ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, @@ -408,6 +433,8 @@ namespace clang { // Importing overrides. void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod); + + FunctionDecl *FindFunctionTemplateSpecialization(FunctionDecl *FromFD); }; template <typename InContainerTy> @@ -437,6 +464,25 @@ bool ASTNodeImporter::ImportTemplateArgumentListInfo< From.arguments(), Result); } +std::tuple<FunctionTemplateDecl *, ASTNodeImporter::OptionalTemplateArgsTy> +ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization( + FunctionDecl *FromFD) { + assert(FromFD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization); + auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); + auto *Template = cast_or_null<FunctionTemplateDecl>( + Importer.Import(FTSInfo->getTemplate())); + + // Import template arguments. + auto TemplArgs = FTSInfo->TemplateArguments->asArray(); + TemplateArgsTy ToTemplArgs; + if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), + ToTemplArgs)) // Error during import. + return std::make_tuple(Template, OptionalTemplateArgsTy()); + + return std::make_tuple(Template, ToTemplArgs); +} + } // namespace clang //---------------------------------------------------------------------------- @@ -2252,23 +2298,17 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD, } case FunctionDecl::TK_FunctionTemplateSpecialization: { - auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); - auto *Template = cast_or_null<FunctionTemplateDecl>( - Importer.Import(FTSInfo->getTemplate())); - if (!Template) - return true; - TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); - - // Import template arguments. - auto TemplArgs = FTSInfo->TemplateArguments->asArray(); - SmallVector<TemplateArgument, 8> ToTemplArgs; - if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), - ToTemplArgs)) + FunctionTemplateDecl* Template; + OptionalTemplateArgsTy ToTemplArgs; + std::tie(Template, ToTemplArgs) = + ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); + if (!Template || !ToTemplArgs) return true; TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy( - Importer.getToContext(), ToTemplArgs); + Importer.getToContext(), *ToTemplArgs); + auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); TemplateArgumentListInfo ToTAInfo; const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten; if (FromTAArgsAsWritten) @@ -2277,6 +2317,7 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD, SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation()); + TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); ToFD->setFunctionTemplateSpecialization( Template, ToTAList, /* InsertPos= */ nullptr, TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, POI); @@ -2312,7 +2353,31 @@ bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD, llvm_unreachable("All cases should be covered!"); } +FunctionDecl * +ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) { + FunctionTemplateDecl* Template; + OptionalTemplateArgsTy ToTemplArgs; + std::tie(Template, ToTemplArgs) = + ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); + if (!Template || !ToTemplArgs) + return nullptr; + + void *InsertPos = nullptr; + auto *FoundSpec = Template->findSpecialization(*ToTemplArgs, InsertPos); + return FoundSpec; +} + Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { + + SmallVector<Decl*, 2> Redecls = getCanonicalForwardRedeclChain(D); + auto RedeclIt = Redecls.begin(); + // Import the first part of the decl chain. I.e. import all previous + // declarations starting from the canonical decl. + for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) + if (!Importer.Import(*RedeclIt)) + return nullptr; + assert(*RedeclIt == D); + // Import the major distinguishing characteristics of this function. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -2323,13 +2388,27 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ToD) return ToD; - const FunctionDecl *FoundWithoutBody = nullptr; - + const FunctionDecl *FoundByLookup = nullptr; + + // If this is a function template specialization, then try to find the same + // existing specialization in the "to" context. The localUncachedLookup + // below will not find any specialization, but would find the primary + // template; thus, we have to skip normal lookup in case of specializations. + // FIXME handle member function templates (TK_MemberSpecialization) similarly? + if (D->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { + if (FunctionDecl *FoundFunction = FindFunctionTemplateSpecialization(D)) { + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody()) + return Importer.Imported(D, FoundFunction); + FoundByLookup = FoundFunction; + } + } // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. - if (!LexicalDC->isFunctionOrMethod()) { + else if (!LexicalDC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (auto *FoundDecl : FoundDecls) { @@ -2341,15 +2420,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { - // FIXME: Actually try to merge the body and other attributes. - const FunctionDecl *FromBodyDecl = nullptr; - D->hasBody(FromBodyDecl); - if (D == FromBodyDecl && !FoundFunction->hasBody()) { - // This function is needed to merge completely. - FoundWithoutBody = FoundFunction; + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody()) + return Importer.Imported(D, FoundFunction); + FoundByLookup = FoundFunction; break; - } - return Importer.Imported(D, FoundFunction); } // FIXME: Check for overloading more carefully, e.g., by boosting @@ -2499,9 +2574,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } ToFunction->setParams(Parameters); - if (FoundWithoutBody) { + if (FoundByLookup) { auto *Recent = const_cast<FunctionDecl *>( - FoundWithoutBody->getMostRecentDecl()); + FoundByLookup->getMostRecentDecl()); ToFunction->setPreviousDecl(Recent); } @@ -2523,10 +2598,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setType(T); } - // Import the body, if any. - if (Stmt *FromBody = D->getBody()) { - if (Stmt *ToBody = Importer.Import(FromBody)) { - ToFunction->setBody(ToBody); + if (D->doesThisDeclarationHaveABody()) { + if (Stmt *FromBody = D->getBody()) { + if (Stmt *ToBody = Importer.Import(FromBody)) { + ToFunction->setBody(ToBody); + } } } @@ -2536,14 +2612,29 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ImportTemplateInformation(D, ToFunction)) return nullptr; - // Add this function to the lexical context. - // NOTE: If the function is templated declaration, it should be not added into - // LexicalDC. But described template is imported during import of - // FunctionTemplateDecl (it happens later). So, we use source declaration - // to determine if we should add the result function. - if (!D->getDescribedFunctionTemplate()) + bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend); + + // TODO Can we generalize this approach to other AST nodes as well? + if (D->getDeclContext()->containsDecl(D)) + DC->addDeclInternal(ToFunction); + if (DC != LexicalDC && D->getLexicalDeclContext()->containsDecl(D)) LexicalDC->addDeclInternal(ToFunction); + // Friend declaration's lexical context is the befriending class, but the + // semantic context is the enclosing scope of the befriending class. + // We want the friend functions to be found in the semantic context by lookup. + // FIXME should we handle this generically in VisitFriendDecl? + // In Other cases when LexicalDC != DC we don't want it to be added, + // e.g out-of-class definitions like void B::f() {} . + if (LexicalDC != DC && IsFriend) { + DC->makeDeclVisibleInContext(ToFunction); + } + + // Import the rest of the chain. I.e. import all subsequent declarations. + for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) + if (!Importer.Import(*RedeclIt)) + return nullptr; + if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D)) ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 7b7febdc410..64fac22bace 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1343,6 +1343,8 @@ bool DeclContext::decls_empty() const { } bool DeclContext::containsDecl(Decl *D) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(); return (D->getLexicalDeclContext() == this && (D->NextInContextAndBits.getPointer() || D == LastDecl)); } |