Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -90,6 +90,13 @@ return getCanonicalForwardRedeclChain(FD); } + void updateAttrAndFlags(const Decl *From, Decl *To) { + // Check if some flags or attrs are new in 'From' and copy into 'To'. + // FIXME: Other flags or attrs? + if (From->isUsed(false) && !To->isUsed(false)) + To->setIsUsed(); + } + class ASTNodeImporter : public TypeVisitor, public DeclVisitor, public StmtVisitor { @@ -3018,6 +3025,7 @@ // An equivalent variable with external linkage has been found. Link // the two declarations, then merge them. Importer.Imported(D, MergeWithVar); + updateAttrAndFlags(D, MergeWithVar); if (VarDecl *DDef = D->getDefinition()) { if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) { @@ -6837,6 +6845,8 @@ if (Pos != ImportedDecls.end()) { Decl *ToD = Pos->second; Importer.ImportDefinitionIfNeeded(FromD, ToD); + // If FromD has some updated flags after last import, apply it. + updateAttrAndFlags(FromD, ToD); return ToD; } Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -290,6 +290,7 @@ std::string FileName; std::unique_ptr Unit; TranslationUnitDecl *TUDecl = nullptr; + std::unique_ptr Importer; TU(StringRef Code, StringRef FileName, ArgVector Args) : Code(Code), FileName(FileName), Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args, @@ -297,6 +298,16 @@ TUDecl(Unit->getASTContext().getTranslationUnitDecl()) { Unit->enableSourceFileDiagnostics(); } + + Decl *import(ASTUnit *ToAST, Decl *FromDecl) { + assert(ToAST); + if (!Importer) { + Importer.reset(new ASTImporter( + ToAST->getASTContext(), ToAST->getFileManager(), + Unit->getASTContext(), Unit->getFileManager(), false)); + } + return Importer->Import(FromDecl); + } }; // We may have several From contexts and related translation units. In each @@ -329,14 +340,10 @@ ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName); ToAST->enableSourceFileDiagnostics(); - ASTContext &FromCtx = FromTU.Unit->getASTContext(), - &ToCtx = ToAST->getASTContext(); + ASTContext &FromCtx = FromTU.Unit->getASTContext(); createVirtualFileIfNeeded(ToAST.get(), InputFileName, FromTU.Code); - ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx, - FromTU.Unit->getFileManager(), false); - IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier); assert(ImportedII && "Declaration with the given identifier " "should be specified in test!"); @@ -347,7 +354,8 @@ assert(FoundDecls.size() == 1); - Decl *Imported = Importer.Import(FoundDecls.front()); + Decl *Imported = FromTU.import(ToAST.get(), FoundDecls.front()); + assert(Imported); return std::make_tuple(*FoundDecls.begin(), Imported); } @@ -401,11 +409,7 @@ assert(It != FromTUs.end()); createVirtualFileIfNeeded(ToAST.get(), It->FileName, It->Code); - ASTContext &FromCtx = From->getASTContext(), - &ToCtx = ToAST->getASTContext(); - ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx, - FromCtx.getSourceManager().getFileManager(), false); - return Importer.Import(From); + return It->import(ToAST.get(), From); } ~ASTImporterTestBase() { @@ -469,6 +473,48 @@ EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2)); } +TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag) { + auto Pattern = varDecl(hasName("x")); + VarDecl *Imported1; + { + Decl *FromTU = getTuDecl("extern int x;", Lang_CXX, "input0.cc"); + auto *FromD = FirstDeclMatcher().match(FromTU, Pattern); + Imported1 = cast(Import(FromD, Lang_CXX)); + } + VarDecl *Imported2; + { + Decl *FromTU = getTuDecl("int x;", Lang_CXX, "input1.cc"); + auto *FromD = FirstDeclMatcher().match(FromTU, Pattern); + Imported2 = cast(Import(FromD, Lang_CXX)); + } + EXPECT_EQ(Imported1->getCanonicalDecl(), Imported2->getCanonicalDecl()); + EXPECT_FALSE(Imported2->isUsed(false)); + { + Decl *FromTU = getTuDecl( + "extern int x; int f() { return x; }", Lang_CXX, "input2.cc"); + auto *FromD = + FirstDeclMatcher().match(FromTU, functionDecl()); + Import(FromD, Lang_CXX); + } + EXPECT_TRUE(Imported2->isUsed(false)); +} + +TEST_P(ASTImporterTestBase, ReimportWithUsedFlag) { + auto Pattern = varDecl(hasName("x")); + + Decl *FromTU = getTuDecl("int x;", Lang_CXX, "input0.cc"); + auto *FromD = FirstDeclMatcher().match(FromTU, Pattern); + + auto *Imported1 = cast(Import(FromD, Lang_CXX)); + + ASSERT_FALSE(Imported1->isUsed(false)); + + FromD->setIsUsed(); + auto *Imported2 = cast(Import(FromD, Lang_CXX)); + + EXPECT_EQ(Imported1, Imported2); + EXPECT_TRUE(Imported2->isUsed(false)); +} TEST_P(ImportExpr, ImportStringLiteral) { MatchVerifier Verifier;