[ASTImporter] Fix import of VarDecl init
Summary:
The init expression of a VarDecl is overwritten in the "To" context if we
import a VarDecl without an init expression (and with a definition). Please
refer to the added tests, especially InitAndDefinitionAreInDifferentTUs. This
patch fixes the malfunction by importing the whole Decl chain similarly as we
did that in case of FunctionDecls. We handle the init expression similarly to
a definition, alas only one init expression will be in the merged ast.
Reviewers: a_sidorin, xazax.hun, r.stahl, a.sidorin
Subscribers: rnkovacs, dkrupp, cfe-commits
Differential Revision: https://reviews.llvm.org/D51597
llvm-svn: 342384
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 96a8d43..366ff7f 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -1828,13 +1828,62 @@
{
Decl *FromTU =
getTuDecl("extern int x; int f() { return x; }", Lang_CXX, "input2.cc");
- auto *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
Import(FromD, Lang_CXX);
}
EXPECT_TRUE(Imported2->isUsed(false));
}
+TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag2) {
+ auto Pattern = varDecl(hasName("x"));
+ VarDecl *ExistingD;
+ {
+ Decl *ToTU = getToTuDecl("int x = 1;", Lang_CXX);
+ ExistingD = FirstDeclMatcher<VarDecl>().match(ToTU, Pattern);
+ }
+ EXPECT_FALSE(ExistingD->isUsed(false));
+ {
+ Decl *FromTU = getTuDecl(
+ "int x = 1; int f() { return x; }", Lang_CXX, "input1.cc");
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ Import(FromD, Lang_CXX);
+ }
+ EXPECT_TRUE(ExistingD->isUsed(false));
+}
+
+TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag3) {
+ auto Pattern = varDecl(hasName("a"));
+ VarDecl *ExistingD;
+ {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ struct A {
+ static const int a = 1;
+ };
+ )", Lang_CXX);
+ ExistingD = FirstDeclMatcher<VarDecl>().match(ToTU, Pattern);
+ }
+ EXPECT_FALSE(ExistingD->isUsed(false));
+ {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct A {
+ static const int a = 1;
+ };
+ const int *f() { return &A::a; } // requires storage,
+ // thus used flag will be set
+ )", Lang_CXX, "input1.cc");
+ auto *FromFunD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern);
+ ASSERT_TRUE(FromD->isUsed(false));
+ Import(FromFunD, Lang_CXX);
+ }
+ EXPECT_TRUE(ExistingD->isUsed(false));
+}
+
TEST_P(ASTImporterTestBase, ReimportWithUsedFlag) {
auto Pattern = varDecl(hasName("x"));
@@ -3244,6 +3293,94 @@
EXPECT_TRUE(ToInitExpr->isGLValue());
}
+struct ImportVariables : ASTImporterTestBase {};
+
+TEST_P(ImportVariables, ImportOfOneDeclBringsInTheWholeChain) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct A {
+ static const int a = 1 + 2;
+ };
+ const int A::a;
+ )", Lang_CXX, "input1.cc");
+
+ auto *FromDWithInit = FirstDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a"))); // Decl with init
+ auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a"))); // Decl with definition
+ ASSERT_NE(FromDWithInit, FromDWithDef);
+ ASSERT_EQ(FromDWithDef->getPreviousDecl(), FromDWithInit);
+
+ auto *ToD0 = cast<VarDecl>(Import(FromDWithInit, Lang_CXX11));
+ auto *ToD1 = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
+ ASSERT_TRUE(ToD0);
+ ASSERT_TRUE(ToD1);
+ EXPECT_NE(ToD0, ToD1);
+ EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+}
+
+TEST_P(ImportVariables, InitAndDefinitionAreInDifferentTUs) {
+ auto StructA =
+ R"(
+ struct A {
+ static const int a = 1 + 2;
+ };
+ )";
+ Decl *ToTU = getToTuDecl(StructA, Lang_CXX);
+ Decl *FromTU = getTuDecl(std::string(StructA) + "const int A::a;", Lang_CXX,
+ "input1.cc");
+
+ auto *FromDWithInit = FirstDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a"))); // Decl with init
+ auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a"))); // Decl with definition
+ ASSERT_EQ(FromDWithInit, FromDWithDef->getPreviousDecl());
+ ASSERT_TRUE(FromDWithInit->getInit());
+ ASSERT_FALSE(FromDWithInit->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDWithDef->isThisDeclarationADefinition());
+ ASSERT_FALSE(FromDWithDef->getInit());
+
+ auto *ToD = FirstDeclMatcher<VarDecl>().match(
+ ToTU, varDecl(hasName("a"))); // Decl with init
+ ASSERT_TRUE(ToD->getInit());
+ ASSERT_FALSE(ToD->getDefinition());
+
+ auto *ImportedD = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
+ EXPECT_TRUE(ImportedD->getAnyInitializer());
+ EXPECT_TRUE(ImportedD->getDefinition());
+}
+
+TEST_P(ImportVariables, InitAndDefinitionAreInTheFromContext) {
+ auto StructA =
+ R"(
+ struct A {
+ static const int a;
+ };
+ )";
+ Decl *ToTU = getToTuDecl(StructA, Lang_CXX);
+ Decl *FromTU = getTuDecl(std::string(StructA) + "const int A::a = 1 + 2;",
+ Lang_CXX, "input1.cc");
+
+ auto *FromDDeclarationOnly = FirstDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a")));
+ auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
+ FromTU, varDecl(hasName("a"))); // Decl with definition and with init.
+ ASSERT_EQ(FromDDeclarationOnly, FromDWithDef->getPreviousDecl());
+ ASSERT_FALSE(FromDDeclarationOnly->getInit());
+ ASSERT_FALSE(FromDDeclarationOnly->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDWithDef->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDWithDef->getInit());
+
+ auto *ToD = FirstDeclMatcher<VarDecl>().match(
+ ToTU, varDecl(hasName("a")));
+ ASSERT_FALSE(ToD->getInit());
+ ASSERT_FALSE(ToD->getDefinition());
+
+ auto *ImportedD = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
+ EXPECT_TRUE(ImportedD->getAnyInitializer());
+ EXPECT_TRUE(ImportedD->getDefinition());
+}
+
struct DeclContextTest : ASTImporterTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
@@ -3623,5 +3760,11 @@
ImportFunctionTemplateSpecializations,
DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportImplicitMethods,
+ DefaultTestValuesForRunOptions, );
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportVariables,
+ DefaultTestValuesForRunOptions, );
+
} // end namespace ast_matchers
} // end namespace clang