Index: include/clang/AST/ExternalASTMerger.h =================================================================== --- include/clang/AST/ExternalASTMerger.h +++ include/clang/AST/ExternalASTMerger.h @@ -44,6 +44,8 @@ FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) override; + + void CompleteType(TagDecl *Tag) override; }; } // end namespace clang Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1622,10 +1622,18 @@ // We may already have a record of the same name; try to find and match it. RecordDecl *AdoptDecl = nullptr; + RecordDecl *PrevDecl = nullptr; if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; SmallVector FoundDecls; DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls); + + if (!FoundDecls.empty()) { + // We're going to have to compare D against potentially conflicting Decls, so complete it. + if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition()) + D->getASTContext().getExternalSource()->CompleteType(D); + } + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -1652,6 +1660,8 @@ } } + PrevDecl = FoundRecord; + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { if ((SearchName && !D->isCompleteDefinition()) || (D->isCompleteDefinition() && @@ -1744,6 +1754,10 @@ LexicalDC->addDeclInternal(D2); if (D->isAnonymousStructOrUnion()) D2->setAnonymousStructOrUnion(true); + if (PrevDecl) { + // FIXME: do this for all Redeclarables, not just RecordDecls. + D2->setPreviousDecl(PrevDecl); + } } Importer.Imported(D, D2); Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -855,6 +855,11 @@ if (CXXRecordDecl *D1CXX = dyn_cast(D1)) { if (CXXRecordDecl *D2CXX = dyn_cast(D2)) { + if (D1CXX->hasExternalLexicalStorage() && + !D1CXX->isCompleteDefinition()) { + D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX); + } + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) Index: lib/AST/ExternalASTMerger.cpp =================================================================== --- lib/AST/ExternalASTMerger.cpp +++ lib/AST/ExternalASTMerger.cpp @@ -178,3 +178,9 @@ } }); } + +void ExternalASTMerger::CompleteType(TagDecl *Tag) { + SmallVector Result; + FindExternalLexicalDecls(Tag, [](Decl::Kind) { return true; }, Result); + Tag->setHasExternalLexicalStorage(false); +} Index: test/Import/conflicting-struct/Inputs/S1.cpp =================================================================== --- /dev/null +++ test/Import/conflicting-struct/Inputs/S1.cpp @@ -0,0 +1,6 @@ +class T; + +class S { + T *t; + int a; +}; Index: test/Import/conflicting-struct/Inputs/S2.cpp =================================================================== --- /dev/null +++ test/Import/conflicting-struct/Inputs/S2.cpp @@ -0,0 +1,7 @@ +class U { + int b; +}; + +class T { + U u; +}; Index: test/Import/conflicting-struct/test.cpp =================================================================== --- /dev/null +++ test/Import/conflicting-struct/test.cpp @@ -0,0 +1,7 @@ +// 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; +} 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 @@ -42,6 +42,10 @@ Imports("import", llvm::cl::ZeroOrMore, llvm::cl::desc("Path to a file containing declarations to import")); +static llvm::cl::opt + Direct("direct", llvm::cl::Optional, + llvm::cl::desc("Use the parsed declarations without indirection")); + static llvm::cl::list ClangArgs("Xcc", llvm::cl::ZeroOrMore, llvm::cl::desc("Argument to pass to the CompilerInvocation"), @@ -172,6 +176,14 @@ return Ins; } +std::unique_ptr +BuildCompilerInstance(ArrayRef ClangArgs) { + std::vector ClangArgv(ClangArgs.size()); + std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), + [](const std::string &s) -> const char * { return s.data(); }); + return init_convenience::BuildCompilerInstance(ClangArgv); +} + std::unique_ptr BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) { auto AST = llvm::make_unique( @@ -205,6 +217,21 @@ CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(); } +std::unique_ptr BuildIndirect(std::unique_ptr &CI) { + std::vector ClangArgv(ClangArgs.size()); + std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), + [](const std::string &s) -> const char * { return s.data(); }); + std::unique_ptr IndirectCI = + init_convenience::BuildCompilerInstance(ClangArgv); + 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); + return IndirectCI; +} + llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI, CodeGenerator &CG) { SourceManager &SM = CI.getSourceManager(); @@ -231,7 +258,9 @@ std::unique_ptr AST = init_convenience::BuildASTContext(*CI, *ST, *BC); CI->setASTContext(AST.release()); - AddExternalSource(*CI, Imports); + if (Imports.size()) { + AddExternalSource(*CI, Imports); + } auto LLVMCtx = llvm::make_unique(); std::unique_ptr CG = @@ -268,8 +297,21 @@ ImportCIs.push_back(std::move(*ImportCI)); } } + std::vector> IndirectCIs; + if (!Direct) { + for (auto &ImportCI : ImportCIs) { + llvm::Expected> IndirectCI = + BuildIndirect(ImportCI); + if (auto E = IndirectCI.takeError()) { + llvm::errs() << llvm::toString(std::move(E)); + exit(-1); + } else { + IndirectCIs.push_back(std::move(*IndirectCI)); + } + } + } llvm::Expected> ExpressionCI = - Parse(Expression, ImportCIs); + Parse(Expression, Direct ? ImportCIs : IndirectCIs); if (auto E = ExpressionCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); @@ -277,3 +319,4 @@ return 0; } } +