Author: martong Date: Tue Jul 17 05:06:36 2018 New Revision: 337267 URL: http://llvm.org/viewvc/llvm-project?rev=337267&view=rev Log: [ASTImporter] Fix import of unnamed structs
Summary: D48773 simplified ASTImporter nicely, but it introduced a new error: Unnamed structs are not imported correctly, if they appear in a recursive context. This patch provides a fix for structural equivalency. Reviewers: a.sidorin, a_sidorin, balazske, gerazo Subscribers: rnkovacs, dkrupp, cfe-commits Differential Revision: https://reviews.llvm.org/D49296 Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp cfe/trunk/unittests/AST/ASTImporterTest.cpp cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=337267&r1=337266&r2=337267&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original) +++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Tue Jul 17 05:06:36 2018 @@ -924,7 +924,7 @@ static bool IsStructurallyEquivalent(Str return false; } - if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + if (!D1->getDeclName() && !D2->getDeclName()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. if (Optional<unsigned> Index1 = Modified: cfe/trunk/unittests/AST/ASTImporterTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=337267&r1=337266&r2=337267&view=diff ============================================================================== --- cfe/trunk/unittests/AST/ASTImporterTest.cpp (original) +++ cfe/trunk/unittests/AST/ASTImporterTest.cpp Tue Jul 17 05:06:36 2018 @@ -273,6 +273,11 @@ public: } }; +template <typename T> RecordDecl *getRecordDecl(T *D) { + auto *ET = cast<ElaboratedType>(D->getType().getTypePtr()); + return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl(); +}; + // This class provides generic methods to write tests which can check internal // attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also, // this fixture makes it possible to import from several "From" contexts. @@ -1755,11 +1760,6 @@ TEST_P(ASTImporterTestBase, ObjectsWithU )", Lang_CXX, "input0.cc"); - auto getRecordDecl = [](VarDecl *VD) { - auto *ET = cast<ElaboratedType>(VD->getType().getTypePtr()); - return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl(); - }; - auto *Obj0 = FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("object0"))); auto *From0 = getRecordDecl(Obj0); @@ -2580,6 +2580,38 @@ TEST_P(ASTImporterTestBase, ImportOfNonE EXPECT_NE(ToM1, ToM2); } +TEST_P(ASTImporterTestBase, ImportUnnamedStructsWithRecursingField) { + Decl *FromTU = getTuDecl( + R"( + struct A { + struct { + struct A *next; + } entry0; + struct { + struct A *next; + } entry1; + }; + )", + Lang_C, "input0.cc"); + auto *From = + FirstDeclMatcher<RecordDecl>().match(FromTU, recordDecl(hasName("A"))); + + Import(From, Lang_C); + + auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); + auto *Entry0 = + FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0"))); + auto *Entry1 = + FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry1"))); + auto *R0 = getRecordDecl(Entry0); + auto *R1 = getRecordDecl(Entry1); + EXPECT_NE(R0, R1); + EXPECT_TRUE(MatchVerifier<RecordDecl>().match( + R0, recordDecl(has(fieldDecl(hasName("next")))))); + EXPECT_TRUE(MatchVerifier<RecordDecl>().match( + R1, recordDecl(has(fieldDecl(hasName("next")))))); +} + struct DeclContextTest : ASTImporterTestBase {}; TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) { Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=337267&r1=337266&r2=337267&view=diff ============================================================================== --- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original) +++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Tue Jul 17 05:06:36 2018 @@ -42,6 +42,21 @@ struct StructuralEquivalenceTest : ::tes return std::make_tuple(D0, D1); } + std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls( + const std::string &SrcCode0, const std::string &SrcCode1, Language Lang) { + this->Code0 = SrcCode0; + this->Code1 = SrcCode1; + ArgVector Args = getBasicRunOptionsForLanguage(Lang); + + const char *const InputFileName = "input.cc"; + + AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName); + AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName); + + return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(), + AST1->getASTContext().getTranslationUnitDecl()); + } + // Get a pair of node pointers into the synthesized AST from the given code // snippets. The same matcher is used for both snippets. template <typename NodeType, typename MatcherType> @@ -62,7 +77,7 @@ struct StructuralEquivalenceTest : ::tes return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher); } - bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) { + bool testStructuralMatch(Decl *D0, Decl *D1) { llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls; StructuralEquivalenceContext Ctx( D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls, @@ -70,7 +85,7 @@ struct StructuralEquivalenceTest : ::tes return Ctx.IsStructurallyEquivalent(D0, D1); } - bool testStructuralMatch(std::tuple<NamedDecl *, NamedDecl *> t) { + bool testStructuralMatch(std::tuple<Decl *, Decl *> t) { return testStructuralMatch(get<0>(t), get<1>(t)); } }; @@ -468,6 +483,11 @@ TEST_F(StructuralEquivalenceCXXMethodTes } struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest { + // FIXME Use a common getRecordDecl with ASTImporterTest.cpp! + RecordDecl *getRecordDecl(FieldDecl *FD) { + auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr()); + return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl(); + }; }; TEST_F(StructuralEquivalenceRecordTest, Name) { @@ -535,6 +555,70 @@ TEST_F(StructuralEquivalenceRecordTest, EXPECT_TRUE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) { + auto t = makeTuDecls( + R"( + struct A { + struct { + struct A *next; + } entry0; + struct { + struct A *next; + } entry1; + }; + )", + "", Lang_C); + auto *TU = get<0>(t); + auto *Entry0 = + FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0"))); + auto *Entry1 = + FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1"))); + auto *R0 = getRecordDecl(Entry0); + auto *R1 = getRecordDecl(Entry1); + + ASSERT_NE(R0, R1); + EXPECT_TRUE(testStructuralMatch(R0, R0)); + EXPECT_TRUE(testStructuralMatch(R1, R1)); + EXPECT_FALSE(testStructuralMatch(R0, R1)); +} + +TEST_F(StructuralEquivalenceRecordTest, + UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) { + auto Code = + R"( + struct A { + struct { + struct A *next; + } entry0; + struct { + struct A *next; + } entry1; + }; + )"; + auto t = makeTuDecls(Code, Code, Lang_C); + + auto *FromTU = get<0>(t); + auto *Entry1 = + FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1"))); + + auto *ToTU = get<1>(t); + auto *Entry0 = + FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0"))); + auto *A = + FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A"))); + A->startDefinition(); // Set isBeingDefined, getDefinition() will return a + // nullptr. This may be the case during ASTImport. + + auto *R0 = getRecordDecl(Entry0); + auto *R1 = getRecordDecl(Entry1); + + ASSERT_NE(R0, R1); + EXPECT_TRUE(testStructuralMatch(R0, R0)); + EXPECT_TRUE(testStructuralMatch(R1, R1)); + EXPECT_FALSE(testStructuralMatch(R0, R1)); +} + + TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) { auto t = makeNamedDecls( "struct A{ }; struct B{ }; void foo(A a, A b);", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits