Index: include/clang/AST/ExternalASTMerger.h =================================================================== --- include/clang/AST/ExternalASTMerger.h +++ include/clang/AST/ExternalASTMerger.h @@ -21,21 +21,29 @@ class ExternalASTMerger : public ExternalASTSource { public: - struct ImporterPair { - std::unique_ptr Forward; - std::unique_ptr Reverse; + struct DCOrigin { + DeclContext *DC; + ASTContext *AST; }; + typedef llvm::DenseMap OriginMap; + typedef std::vector> ImporterVector; private: - std::vector Importers; + ImporterVector Importers; + OriginMap Origins; public: - struct ImporterEndpoint { + struct ImporterTarget { ASTContext &AST; FileManager &FM; }; - ExternalASTMerger(const ImporterEndpoint &Target, - llvm::ArrayRef Sources); + struct ImporterSource { + ASTContext &AST; + FileManager &FM; + const OriginMap &OM; + }; + ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef Sources); bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; @@ -44,6 +52,20 @@ FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) override; + + void CompleteType(clang::TagDecl *Tag) override; + + void MaybeRecordOrigin(DeclContext *ToDC, DCOrigin Origin); + void ForceRecordOrigin(DeclContext *ToDC, DCOrigin Origin); + const OriginMap &GetOrigins() { return Origins; } + + bool HasImporterForOrigin(ASTContext &OriginContext); + ASTImporter &ImporterForOrigin(ASTContext &OriginContext); +private: + void RecordOriginImpl(DeclContext *ToDC, DCOrigin Origin, + ASTImporter &importer); + template + void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); }; } // 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,42 +76,152 @@ } 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; } } -template -void ForEachMatchingDC( - const DeclContext *DC, - 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); +class LazyASTImporter : public ASTImporter { +private: + ExternalASTMerger &Parent; + ASTImporter Reverse; + const ExternalASTMerger::OriginMap &FromOrigins; +public: + LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, + FileManager &ToFileManager, ASTContext &FromContext, + FileManager &FromFileManager, + const ExternalASTMerger::OriginMap &_FromOrigins) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + /*MinimalImport=*/true), + Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext, + ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {} + Decl *Imported(Decl *From, Decl *To) override { + if (auto *ToDC = dyn_cast(To)) { + Source FromDC( + cast(From)->getPrimaryContext()); + if (FromOrigins.count(FromDC) && + Parent.HasImporterForOrigin(*FromOrigins.lookup(FromDC).AST)) + Parent.ForceRecordOrigin(ToDC, FromOrigins.lookup(FromDC)); + else + Parent.MaybeRecordOrigin(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); } -} + ASTImporter &GetReverse() { return Reverse; } +}; bool HasDeclOfSameType(llvm::ArrayRef Decls, const Candidate &C) { return llvm::any_of(Decls, [&](const Candidate &D) { return C.first.get()->getKind() == D.first.get()->getKind(); }); } + } // 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(S.AST, S.FM, Target.AST, Target.FM, - /*MinimalImport=*/true)}); +ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr &I : Importers) { + if (&I->getFromContext() == &OriginContext) + return *I; } + llvm_unreachable("We should have an importer for this origin!"); } +bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr &I : Importers) { + if (&I->getFromContext() == &OriginContext) + return true; + } + return false; +} + +template +void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, + CallbackType Callback) { + if (Origins.count(DC)) { + ExternalASTMerger::DCOrigin Origin = Origins[DC]; + ASTImporter &Importer = ImporterForOrigin(*Origin.AST); + Callback(Importer, static_cast(Importer).GetReverse(), + Origin.DC); + } else { + bool DidCallback = false; + for (const std::unique_ptr &Importer : Importers) { + Source SourceTU = + Importer->getFromContext().getTranslationUnitDecl(); + ASTImporter &Reverse = + static_cast(Importer.get())->GetReverse(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) { + DidCallback = true; + Callback(*Importer, Reverse, SourceDC); + } + } + assert(DidCallback && "Couldn't find a source context matching our DC"); + } +} + +void ExternalASTMerger::CompleteType(clang::TagDecl *Tag) { + if (!Tag->hasExternalLexicalStorage()) + return; // We can get called for TagDecls we didn't import. + bool DidComplete = false; + ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) { + if (DidComplete) + return; + if (!isa(SourceDC.get())) + return; + auto *SourceTag = const_cast(cast(SourceDC.get())); + if (SourceTag->hasExternalLexicalStorage()) + SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); + if (!SourceTag->getDefinition()) + return; + DidComplete = true; + Forward.Imported(SourceTag, Tag); + Forward.ImportDefinition(SourceTag); + Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); + }); +} + +void ExternalASTMerger::MaybeRecordOrigin(DeclContext *ToDC, DCOrigin Origin) { + ASTImporter &Importer = ImporterForOrigin(*Origin.AST); + ASTImporter &Reverse = + static_cast(Importer).GetReverse(); + Source FoundFromDC = + LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse); + if (FoundFromDC) { + assert(FoundFromDC == Origin.DC && "Found a different FromDC!"); + } else { + RecordOriginImpl(ToDC, Origin, Importer); + } +} + +void ExternalASTMerger::ForceRecordOrigin(DeclContext *ToDC, + DCOrigin Origin) { + RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST)); +} + +void ExternalASTMerger::RecordOriginImpl(DeclContext *ToDC, DCOrigin Origin, + ASTImporter &Importer) { + Origins[ToDC] = Origin; + Importer.ASTImporter::Imported(cast(Origin.DC), cast(ToDC)); +} + +ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef Sources) { + for (const ImporterSource &S : Sources) { + Importers.push_back(llvm::make_unique( + *this, Target.AST, Target.FM, S.AST, S.FM, S.OM)); + } +} + bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { llvm::SmallVector Decls; @@ -140,15 +238,14 @@ } }; - ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source SourceDC) { - DeclarationName FromName = IP.Reverse->Import(Name); - DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); - for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, IP.Forward.get())); - } - }); + ForEachMatchingDC(DC, [&](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, &Forward)); + } + }); llvm::ArrayRef DeclsToReport = CompleteDecls.empty() ? ForwardDecls : CompleteDecls; @@ -170,17 +267,14 @@ void ExternalASTMerger::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) { - ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source SourceDC) { - for (const Decl *SourceDecl : SourceDC.get()->decls()) { - if (IsKindWeWant(SourceDecl->getKind())) { - Decl *ImportedDecl = - IP.Forward->Import(const_cast(SourceDecl)); - assert(ImportedDecl->getDeclContext() == DC); - (void)ImportedDecl; - } - } - }); + ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) { + for (const Decl *SourceDecl : SourceDC.get()->decls()) { + if (IsKindWeWant(SourceDecl->getKind())) { + Decl *ImportedDecl = Forward.Import(const_cast(SourceDecl)); + assert(ImportedDecl->getDeclContext() == DC); + (void)ImportedDecl; + } + } + }); } - Index: test/Import/local-struct-use-origins/test.cpp =================================================================== --- test/Import/local-struct-use-origins/test.cpp +++ test/Import/local-struct-use-origins/test.cpp @@ -1,7 +1,6 @@ -// RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s -// XFAIL: * +// RUN: clang-import-test -dump-ir -use-origins -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s // 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: 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: test/Import/struct-and-var/Inputs/S1.cpp =================================================================== --- test/Import/struct-and-var/Inputs/S1.cpp +++ test/Import/struct-and-var/Inputs/S1.cpp @@ -1,6 +1 @@ -class T; - -class S { - T *t; - int a; -}; +int F; Index: test/Import/struct-and-var/Inputs/S2.cpp =================================================================== --- test/Import/struct-and-var/Inputs/S2.cpp +++ test/Import/struct-and-var/Inputs/S2.cpp @@ -1,7 +1,3 @@ -class U { - int b; +struct F { + int a; }; - -class T { - U u; -}; Index: test/Import/struct-and-var/test.cpp =================================================================== --- test/Import/struct-and-var/test.cpp +++ test/Import/struct-and-var/test.cpp @@ -1,7 +1,5 @@ // RUN: clang-import-test --import %S/Inputs/S1.cpp --import %S/Inputs/S2.cpp -expression %s void expr() { - S MyS; - T MyT; - MyS.a = 3; - MyT.u.b = 2; + struct F f; + int x = f.a; } Index: test/Import/template/Inputs/T.cpp =================================================================== --- test/Import/template/Inputs/T.cpp +++ test/Import/template/Inputs/T.cpp @@ -1,14 +1,5 @@ template struct A { -}; - -template <> struct A { struct B { - int f; + T f; }; }; - -template <> struct A { - struct B { - int g; - }; -}; Index: test/Import/template/test.cpp =================================================================== --- test/Import/template/test.cpp +++ test/Import/template/test.cpp @@ -1,7 +1,4 @@ // RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s -// XFAIL: * void expr() { - A::B b1; - A::B b2; - b1.f + b2.g; + A::B b; } 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,8 +48,12 @@ 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::opt + UseOrigins("use-origins", llvm::cl::Optional, + llvm::cl::desc("Use DeclContext origin information for more accurate lookups")); + static llvm::cl::list ClangArgs("Xcc", llvm::cl::ZeroOrMore, llvm::cl::desc("Argument to pass to the CompilerInvocation"), @@ -60,13 +64,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 +156,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 +228,48 @@ } // end namespace namespace { - -void AddExternalSource( - CompilerInstance &CI, - llvm::ArrayRef> Imports) { - ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()}); - llvm::SmallVector Sources; - for (const std::unique_ptr &CI : Imports) { - Sources.push_back({CI->getASTContext(), CI->getFileManager()}); + +struct CIAndOrigins { + using OriginMap = clang::ExternalASTMerger::OriginMap; + std::unique_ptr CI; + + ASTContext &getASTContext() { return CI->getASTContext(); } + FileManager &getFileManager() { return CI->getFileManager(); } + const OriginMap &getOriginMap() { + static const OriginMap EmptyOriginMap; + if (ExternalASTSource *Source = CI->getASTContext().getExternalSource()) + return static_cast(Source)->GetOrigins(); + else + return EmptyOriginMap; } + DiagnosticConsumer &getDiagnosticClient() { + return CI->getDiagnosticClient(); + } + CompilerInstance &getCompilerInstance() { return *CI; } +}; + +void AddExternalSource(CIAndOrigins &CI, + llvm::MutableArrayRef Imports) { + ExternalASTMerger::ImporterTarget Target( + {CI.getASTContext(), CI.getFileManager()}); + llvm::SmallVector Sources; + for (CIAndOrigins &Import : Imports) { + Sources.push_back( + {Import.getASTContext(), Import.getFileManager(), Import.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()}; 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 +286,41 @@ 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()}; 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 +334,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,15 +344,21 @@ ImportCIs.push_back(std::move(*ImportCI)); } } - std::vector> IndirectCIs; - if (!Direct) { + std::vector IndirectCIs; + if (!Direct || UseOrigins) { for (auto &ImportCI : ImportCIs) { - std::unique_ptr IndirectCI = BuildIndirect(ImportCI); + CIAndOrigins IndirectCI = BuildIndirect(ImportCI); IndirectCIs.push_back(std::move(IndirectCI)); } } - llvm::Expected> ExpressionCI = - Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST, DumpIR); + if (UseOrigins) { + for (auto &ImportCI : ImportCIs) { + IndirectCIs.push_back(std::move(ImportCI)); + } + } + llvm::Expected ExpressionCI = + Parse(Expression, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs, + DumpAST, DumpIR); if (auto E = ExpressionCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); @@ -341,4 +366,3 @@ return 0; } } -