diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1942,6 +1942,17 @@ ImportedOrErr.takeError()); } + // Finally re-order everything by lexical order. + for (auto *D : FromDC->decls()) { + assert(D && "DC contains a null decl"); + if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D); + ToD && ToDC == ToD->getLexicalDeclContext() && + ToDC->containsDecl(ToD)) { + ToDC->removeDecl(ToD); + ToDC->addDeclInternal(ToD); + } + } + return ChildErrors; } diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -1462,11 +1462,18 @@ MatchVerifier{}.match(To->getTranslationUnitDecl(), Pattern)); } -AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector, Order) { +AST_MATCHER_P(RecordDecl, hasLexicalOrder, std::vector, Order) { size_t Index = 0; for (Decl *D : Node.decls()) { - if (isa(D) || isa(D)) { - auto *ND = cast(D); + if (isa(D) || isa(D) || !D->isImplicit()) { + NamedDecl *ND = nullptr; + if (isa(D)) + ND = cast(D); + else if (auto *Friend = dyn_cast(D); + Friend && !(ND = Friend->getFriendDecl())) + ND = Friend->getFriendType()->getType()->getAsRecordDecl(); + if (!ND) + return false; if (Index == Order.size()) return false; if (ND->getName() != Order[Index]) @@ -1513,8 +1520,8 @@ Lang_CXX11, "", Lang_CXX11); MatchVerifier Verifier; - ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"})))); - EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"})))); + ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasLexicalOrder({"a", "b"})))); + EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasLexicalOrder({"a", "b"})))); } TEST_P(ASTImporterOptionSpecificTestBase, @@ -1532,19 +1539,46 @@ )s", Lang_CXX11, "", Lang_CXX11); + auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "b", "c"})); MatchVerifier Verifier; - ASSERT_TRUE( - Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"})))); - EXPECT_TRUE( - Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"})))); + ASSERT_TRUE(Verifier.match(From, Pattern)); + EXPECT_TRUE(Verifier.match(To, Pattern)); +} + +TEST_P(ASTImporterOptionSpecificTestBase, CXXRecordDeclCorrectLexicalOrder) { + Decl *From, *To; + std::tie(From, To) = getImportedDecl( + R"s( + struct declToImport { + int a = c; + void b() { d(); } + int c = 1; + void d(); + friend class e; + int f = 2; + enum { + g, h + }; + class I {}; + enum J { + k, l + }; + template class M; + }; + )s", + Lang_CXX11, "", Lang_CXX11); + + auto Pattern = cxxRecordDecl( + hasLexicalOrder({"a", "b", "c", "d", "e", "f", "", "I", "J", "M"})); + MatchVerifier Verifier; + ASSERT_TRUE(Verifier.match(From, Pattern)); + EXPECT_TRUE(Verifier.match(To, Pattern)); } TEST_P(ASTImporterOptionSpecificTestBase, CXXRecordDeclFieldAndIndirectFieldOrder) { Decl *From, *To; std::tie(From, To) = getImportedDecl( - // First field is "a", then the field for unnamed union, then "b" and "c" - // from it (indirect fields), then "d". R"s( struct declToImport { int a = d; @@ -1557,11 +1591,14 @@ )s", Lang_CXX11, "", Lang_CXX11); + auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "", /* anonymous union */ + "", /* implicit field */ + "b", /* indirect field */ + "c", /* indirect field */ + "d"})); MatchVerifier Verifier; - ASSERT_TRUE(Verifier.match( - From, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"})))); - EXPECT_TRUE(Verifier.match( - To, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"})))); + ASSERT_TRUE(Verifier.match(From, Pattern)); + EXPECT_TRUE(Verifier.match(To, Pattern)); } TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) { @@ -3007,7 +3044,7 @@ " int a = 5;" "};", Lang_CXX11, "", Lang_CXX11, Verifier, - recordDecl(hasFieldOrder({"b", "a"}))); + recordDecl(hasLexicalOrder({"b", "a"}))); } const internal::VariadicDynCastAllOfMatcher