Index: include/clang/AST/ExternalASTMerger.h =================================================================== --- include/clang/AST/ExternalASTMerger.h +++ include/clang/AST/ExternalASTMerger.h @@ -26,13 +26,21 @@ std::unique_ptr Reverse; }; + struct DCOrigin { + DeclContext *DC; + ASTContext *AST; + }; + + typedef llvm::DenseMap OriginMap; private: std::vector Importers; + OriginMap Origins; public: struct ImporterEndpoint { ASTContext &AST; FileManager &FM; + OriginMap &OM; }; ExternalASTMerger(const ImporterEndpoint &Target, llvm::ArrayRef Sources); @@ -44,6 +52,8 @@ FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) override; + + const OriginMap &GetOrigins() { return Origins; } }; } // end namespace clang Index: lib/AST/ExternalASTMerger.cpp =================================================================== --- lib/AST/ExternalASTMerger.cpp +++ lib/AST/ExternalASTMerger.cpp @@ -32,26 +32,6 @@ typedef std::pair, ASTImporter *> Candidate; -class LazyASTImporter : public ASTImporter { -public: - LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager, - ASTContext &FromContext, FileManager &FromFileManager) - : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, - /*MinimalImport=*/true) {} - Decl *Imported(Decl *From, Decl *To) override { - if (auto ToTag = dyn_cast(To)) { - ToTag->setHasExternalLexicalStorage(); - ToTag->setMustBuildLookupTable(); - } else if (auto ToNamespace = dyn_cast(To)) { - ToNamespace->setHasExternalVisibleStorage(); - } else if (auto ToContainer = dyn_cast(To)) { - ToContainer->setHasExternalLexicalStorage(); - ToContainer->setMustBuildLookupTable(); - } - return ASTImporter::Imported(From, To); - } -}; - Source LookupSameContext(Source SourceTU, const DeclContext *DC, ASTImporter &ReverseImporter) { @@ -70,15 +50,23 @@ DeclContext::lookup_result SearchResult = SourceParentDC.get()->lookup(SourceName.get()); size_t SearchResultSize = SearchResult.size(); - // Handle multiple candidates once we have a test for it. - // This may turn up when we import template specializations correctly. - assert(SearchResultSize < 2); - if (SearchResultSize == 0) { - // couldn't find the name, so we have to give up + if (SearchResultSize == 0 || SearchResultSize > 1) { + // There are two cases here. First, we might not find the name. + // We might also find multiple copies, in which case we have no + // guarantee that the one we wanted is the one we pick. (E.g., + // if we have two specializations of the same templae it is + // very hard to determine which is the one you want.) + // + // Since we have the Origins map, the most reliable solution here + // is to rely on that and give up on being able to find better + // versios elsewhere. return nullptr; } else { NamedDecl *SearchResultDecl = SearchResult[0]; - return dyn_cast(SearchResultDecl); + if (isa(SearchResultDecl)) + return cast(SearchResultDecl)->getPrimaryContext(); + else + return nullptr; // This type of lookup is unsupported } } @@ -88,22 +76,54 @@ } else if (auto FD = dyn_cast(D)) { return !FD->isThisDeclarationADefinition(); } else if (auto OID = dyn_cast(D)) { - return OID->isThisDeclarationADefinition(); + return OID->isThisDeclarationADefinition(); } else { return false; } } +struct UnownedImporterPair { + ASTImporter *Forward = nullptr; + ASTImporter *Reverse = nullptr; + + UnownedImporterPair(const ExternalASTMerger::ImporterPair &Pair) + : Forward(Pair.Forward.get()), Reverse(Pair.Reverse.get()) {} + UnownedImporterPair() {} + + bool IsValid() { return Forward && Reverse; } +}; + +UnownedImporterPair +ImportersForOrigin(llvm::ArrayRef Importers, + ASTContext &OriginContext) { + for (const ExternalASTMerger::ImporterPair &IP : Importers) { + if (&IP.Forward->getFromContext() == &OriginContext) + return UnownedImporterPair(IP); + } + return {}; +} + template void ForEachMatchingDC( - const DeclContext *DC, + const DeclContext *DC, ExternalASTMerger::OriginMap &Origins, llvm::ArrayRef Importers, CallbackType Callback) { - for (const ExternalASTMerger::ImporterPair &IP : Importers) { - Source SourceTU = - IP.Forward->getFromContext().getTranslationUnitDecl(); - if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) - Callback(IP, SourceDC); + if (Origins.count(DC)) { + ExternalASTMerger::DCOrigin Origin = Origins[DC]; + UnownedImporterPair IP = ImportersForOrigin(Importers, *Origin.AST); + assert(IP.IsValid() && "We shoud have an importer for this origin!"); + Callback(*IP.Forward, *IP.Reverse, Origin.DC); + } else { + bool DidCallback = false; + for (const ExternalASTMerger::ImporterPair &IP : Importers) { + Source SourceTU = + IP.Forward->getFromContext().getTranslationUnitDecl(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) { + DidCallback = true; + Callback(*IP.Forward, *IP.Reverse, SourceDC); + } + } + assert(DidCallback && "Couldn't find a source context matching our DC"); } } @@ -112,15 +132,63 @@ return C.first.get()->getKind() == D.first.get()->getKind(); }); } + +class LazyASTImporter : public ASTImporter { +private: + ExternalASTMerger::OriginMap *Origins; + ExternalASTMerger::OriginMap *FromOrigins; + ASTImporter *Reverse; + +public: + LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + ExternalASTMerger::OriginMap &_Origins, + ExternalASTMerger::OriginMap &_FromOrigins) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + /*MinimalImport=*/true), + Origins(&_Origins), FromOrigins(&_FromOrigins) {} + Decl *Imported(Decl *From, Decl *To) override { + assert(Origins && Reverse && "Must initialize Origins and Reverse!"); + if (auto *ToDC = dyn_cast(To)) { + Source FromDC( + cast(From)->getPrimaryContext()); + if (FromOrigins->count(FromDC)) { + (*Origins)[ToDC] = (*FromOrigins)[FromDC]; + } + Source FoundFromDC = LookupSameContext( + getFromContext().getTranslationUnitDecl(), ToDC, *Reverse); + if (FoundFromDC) { + assert(FoundFromDC == FromDC && "Found a different FromDC!"); + } else { + (*Origins)[ToDC] = {FromDC, &getFromContext()}; + } + } + if (auto ToTag = dyn_cast(To)) { + ToTag->setHasExternalLexicalStorage(); + ToTag->setMustBuildLookupTable(); + } else if (auto ToNamespace = dyn_cast(To)) { + ToNamespace->setHasExternalVisibleStorage(); + } else if (auto ToContainer = dyn_cast(To)) { + ToContainer->setHasExternalLexicalStorage(); + ToContainer->setMustBuildLookupTable(); + } + return ASTImporter::Imported(From, To); + } + void InstallReverse(ASTImporter *_Reverse) { Reverse = _Reverse; } +}; + } // end namespace ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, llvm::ArrayRef Sources) { for (const ImporterEndpoint &S : Sources) { Importers.push_back( - {llvm::make_unique(Target.AST, Target.FM, S.AST, S.FM), + {llvm::make_unique(Target.AST, Target.FM, S.AST, S.FM, + Origins, S.OM), llvm::make_unique(S.AST, S.FM, Target.AST, Target.FM, /*MinimalImport=*/true)}); + static_cast(Importers.back().Forward.get()) + ->InstallReverse(Importers.back().Reverse.get()); } } @@ -141,12 +209,12 @@ }; ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source SourceDC) { - DeclarationName FromName = IP.Reverse->Import(Name); + DC, Origins, Importers, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) { + DeclarationName FromName = Reverse.Import(Name); DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); + FilterFoundDecl(std::make_pair(FromD, &Forward)); } }); @@ -171,16 +239,14 @@ const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) { ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source SourceDC) { + DC, Origins, Importers, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) { for (const Decl *SourceDecl : SourceDC.get()->decls()) { if (IsKindWeWant(SourceDecl->getKind())) { - Decl *ImportedDecl = - IP.Forward->Import(const_cast(SourceDecl)); + Decl *ImportedDecl = Forward.Import(const_cast(SourceDecl)); assert(ImportedDecl->getDeclContext() == DC); (void)ImportedDecl; } } }); } - Index: test/Import/local-struct/test.cpp =================================================================== --- test/Import/local-struct/test.cpp +++ test/Import/local-struct/test.cpp @@ -1,7 +1,6 @@ // RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s -// XFAIL: * // CHECK: %struct.S = type { i -// CHECK: %struct.S.0 = type { i1 } +// CHECK: %struct.S.0 = type { i void foo() { return Bar().bar(3, true); Index: tools/clang-import-test/clang-import-test.cpp =================================================================== --- tools/clang-import-test/clang-import-test.cpp +++ tools/clang-import-test/clang-import-test.cpp @@ -48,7 +48,7 @@ static llvm::cl::opt Direct("direct", llvm::cl::Optional, - llvm::cl::desc("Use the parsed declarations without indirection")); + llvm::cl::desc("Use the parsed declarations without indirection")); static llvm::cl::list ClangArgs("Xcc", llvm::cl::ZeroOrMore, @@ -60,13 +60,11 @@ llvm::cl::desc("The language to parse (default: c++)"), llvm::cl::init("c++")); -static llvm::cl::opt -DumpAST("dump-ast", llvm::cl::init(false), - llvm::cl::desc("Dump combined AST")); +static llvm::cl::opt DumpAST("dump-ast", llvm::cl::init(false), + llvm::cl::desc("Dump combined AST")); -static llvm::cl::opt -DumpIR("dump-ir", llvm::cl::init(false), - llvm::cl::desc("Dump IR from final parse")); +static llvm::cl::opt DumpIR("dump-ir", llvm::cl::init(false), + llvm::cl::desc("Dump IR from final parse")); namespace init_convenience { class TestDiagnosticConsumer : public DiagnosticConsumer { @@ -154,8 +152,7 @@ } }; -std::unique_ptr -BuildCompilerInstance() { +std::unique_ptr BuildCompilerInstance() { auto Ins = llvm::make_unique(); auto DC = llvm::make_unique(); const bool ShouldOwnClient = true; @@ -227,29 +224,43 @@ } // end namespace namespace { - -void AddExternalSource( - CompilerInstance &CI, - llvm::ArrayRef> Imports) { - ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()}); + +struct CIAndOrigins { + using OriginMap = clang::ExternalASTMerger::OriginMap; + std::unique_ptr CI; + OriginMap OM; + ASTContext &getASTContext() { return CI->getASTContext(); } + FileManager &getFileManager() { return CI->getFileManager(); } + OriginMap &getOriginMap() { return OM; } + DiagnosticConsumer &getDiagnosticClient() { + return CI->getDiagnosticClient(); + } + CompilerInstance &getCompilerInstance() { return *CI; } +}; + +void AddExternalSource(CIAndOrigins &CI, + llvm::MutableArrayRef Imports) { + ExternalASTMerger::ImporterEndpoint Target( + {CI.getASTContext(), CI.getFileManager(), CI.getOriginMap()}); llvm::SmallVector Sources; - for (const std::unique_ptr &CI : Imports) { - Sources.push_back({CI->getASTContext(), CI->getFileManager()}); + for (CIAndOrigins &CI : Imports) { + Sources.push_back( + {CI.getASTContext(), CI.getFileManager(), CI.getOriginMap()}); } auto ES = llvm::make_unique(Target, Sources); CI.getASTContext().setExternalSource(ES.release()); CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(); } -std::unique_ptr BuildIndirect(std::unique_ptr &CI) { - std::unique_ptr IndirectCI = - init_convenience::BuildCompilerInstance(); +CIAndOrigins BuildIndirect(CIAndOrigins &CI) { + CIAndOrigins IndirectCI{init_convenience::BuildCompilerInstance(), + ExternalASTMerger::OriginMap()}; auto ST = llvm::make_unique(); auto BC = llvm::make_unique(); - std::unique_ptr AST = - init_convenience::BuildASTContext(*IndirectCI, *ST, *BC); - IndirectCI->setASTContext(AST.release()); - AddExternalSource(*IndirectCI, CI); + std::unique_ptr AST = init_convenience::BuildASTContext( + IndirectCI.getCompilerInstance(), *ST, *BC); + IndirectCI.getCompilerInstance().setASTContext(AST.release()); + AddExternalSource(IndirectCI, CI); return IndirectCI; } @@ -266,41 +277,42 @@ return llvm::Error::success(); } -llvm::Expected> -Parse(const std::string &Path, - llvm::ArrayRef> Imports, - bool ShouldDumpAST, bool ShouldDumpIR) { - std::unique_ptr CI = - init_convenience::BuildCompilerInstance(); +llvm::Expected Parse(const std::string &Path, + llvm::MutableArrayRef Imports, + bool ShouldDumpAST, bool ShouldDumpIR) { + CIAndOrigins CI{init_convenience::BuildCompilerInstance(), + ExternalASTMerger::OriginMap()}; auto ST = llvm::make_unique(); auto BC = llvm::make_unique(); std::unique_ptr AST = - init_convenience::BuildASTContext(*CI, *ST, *BC); - CI->setASTContext(AST.release()); + init_convenience::BuildASTContext(CI.getCompilerInstance(), *ST, *BC); + CI.getCompilerInstance().setASTContext(AST.release()); if (Imports.size()) - AddExternalSource(*CI, Imports); + AddExternalSource(CI, Imports); std::vector> ASTConsumers; auto LLVMCtx = llvm::make_unique(); - ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx)); - auto &CG = *static_cast(ASTConsumers.back().get()); + ASTConsumers.push_back( + init_convenience::BuildCodeGen(CI.getCompilerInstance(), *LLVMCtx)); + auto &CG = *static_cast(ASTConsumers.back().get()); if (ShouldDumpAST) ASTConsumers.push_back(CreateASTDumper("", true, false, false)); - CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(), - &CI->getPreprocessor()); + CI.getDiagnosticClient().BeginSourceFile( + CI.getCompilerInstance().getLangOpts(), + &CI.getCompilerInstance().getPreprocessor()); MultiplexConsumer Consumers(std::move(ASTConsumers)); - Consumers.Initialize(CI->getASTContext()); + Consumers.Initialize(CI.getASTContext()); - if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) { + if (llvm::Error PE = ParseSource(Path, CI.getCompilerInstance(), Consumers)) { return std::move(PE); } - CI->getDiagnosticClient().EndSourceFile(); + CI.getDiagnosticClient().EndSourceFile(); if (ShouldDumpIR) CG.GetModule()->print(llvm::outs(), nullptr); - if (CI->getDiagnosticClient().getNumErrors()) { + if (CI.getDiagnosticClient().getNumErrors()) { return llvm::make_error( "Errors occured while parsing the expression.", std::error_code()); } else { @@ -314,10 +326,9 @@ const bool DisableCrashReporting = true; llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting); llvm::cl::ParseCommandLineOptions(argc, argv); - std::vector> ImportCIs; + std::vector ImportCIs; for (auto I : Imports) { - llvm::Expected> ImportCI = - Parse(I, {}, false, false); + llvm::Expected ImportCI = Parse(I, {}, false, false); if (auto E = ImportCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); @@ -325,14 +336,14 @@ ImportCIs.push_back(std::move(*ImportCI)); } } - std::vector> IndirectCIs; + std::vector IndirectCIs; if (!Direct) { for (auto &ImportCI : ImportCIs) { - std::unique_ptr IndirectCI = BuildIndirect(ImportCI); + CIAndOrigins IndirectCI = BuildIndirect(ImportCI); IndirectCIs.push_back(std::move(IndirectCI)); } } - llvm::Expected> ExpressionCI = + llvm::Expected ExpressionCI = Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST, DumpIR); if (auto E = ExpressionCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); @@ -341,4 +352,3 @@ return 0; } } -