Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1635,13 +1635,61 @@ auto ToDCOrErr = Importer.ImportContext(FromDC); return ToDCOrErr.takeError(); } - llvm::SmallVector ImportedDecls; + + const auto *FromRD = dyn_cast(FromDC); for (auto *From : FromDC->decls()) { ExpectedDecl ImportedOrErr = import(From); - if (!ImportedOrErr) + if (!ImportedOrErr) { + // For RecordDecls, failed import of a field will break the layout of the + // structure. Handle it as an error. + if (FromRD) + return ImportedOrErr.takeError(); // Ignore the error, continue with next Decl. // FIXME: Handle this case somehow better. - consumeError(ImportedOrErr.takeError()); + else + consumeError(ImportedOrErr.takeError()); + } + } + + // Reorder declarations in RecordDecls because they may have another + // order. Keeping field order is vitable because it determines structure + // layout. + // FIXME: This is an ugly fix. Unfortunately, I cannot come with better + // solution for this issue. We cannot defer expression import here because + // type import can depend on them. + if (!FromRD) + return Error::success(); + + + // NOTE: Here and below, we cannot call field_begin() method and its callers + // on ToRD if it has an external storage. Calling field_begin() will + // automatically load all the fields by calling + // LoadFieldsFromExternalStorage(). + auto ImportedDC = import(cast(FromDC)); + assert(ImportedDC); + auto *ToRD = cast(*ImportedDC); + for (auto *D : FromRD->decls()) { + if (isa(D) || isa(D)) { + Decl *ToD = Importer.GetAlreadyImportedOrNull(D); + assert(ToRD == ToD->getDeclContext() && ToRD->containsDecl(ToD)); + ToRD->removeDecl(ToD); + } + } + + if (!ToRD->hasExternalLexicalStorage()) + assert(ToRD->field_empty()); + + for (auto *D : FromRD->decls()) { + if (isa(D) || isa(D)) { + Decl *ToD = Importer.GetAlreadyImportedOrNull(D); + assert(ToD); + assert(ToRD == ToD->getDeclContext()); + assert(ToRD == ToD->getLexicalDeclContext()); + if (!ToRD->hasExternalLexicalStorage()) + assert(!ToRD->containsDecl(ToD)); + + ToRD->addDeclInternal(ToD); + } } return Error::success(); Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -1537,7 +1537,7 @@ } TEST_P(ASTImporterOptionSpecificTestBase, - DISABLED_CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) { + CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) { Decl *From, *To; std::tie(From, To) = getImportedDecl( // The original recursive algorithm of ASTImporter first imports 'c' then @@ -5517,5 +5517,16 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportVariables, DefaultTestValuesForRunOptions, ); +TEST_P(ImportDecl, ImportFieldOrder) { + MatchVerifier Verifier; + testImport("struct declToImport {" + " int b = a + 2;" + " int a = 5;" + "};", + Lang_CXX11, "", Lang_CXX11, Verifier, + recordDecl(hasFieldOrder({"b", "a"}))); +} + + } // end namespace ast_matchers } // end namespace clang