[ASTImporter] Reorder fields after structure import is finished
There are multiple reasons why field structures can be imported
in wrong order. The simplest is the ability of field initializers
and method bodies to refer fields not in order they are listed in.
Unfortunately, there is no clean solution for that currently
so I'm leaving a FIXME.
Differential Revision: https://reviews.llvm.org/D44100
llvm-svn: 345545
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 49623d0..b5f9472 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1658,13 +1658,53 @@
auto ToDCOrErr = Importer.ImportContext(FromDC);
return ToDCOrErr.takeError();
}
- llvm::SmallVector<Decl *, 8> ImportedDecls;
+
+ const auto *FromRD = dyn_cast<RecordDecl>(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();
+
+ auto ImportedDC = import(cast<Decl>(FromDC));
+ assert(ImportedDC);
+ auto *ToRD = cast<RecordDecl>(*ImportedDC);
+
+ for (auto *D : FromRD->decls()) {
+ if (isa<FieldDecl>(D) || isa<FriendDecl>(D)) {
+ Decl *ToD = Importer.GetAlreadyImportedOrNull(D);
+ assert(ToRD == ToD->getDeclContext() && ToRD->containsDecl(ToD));
+ ToRD->removeDecl(ToD);
+ }
+ }
+
+ assert(ToRD->field_empty());
+
+ for (auto *D : FromRD->decls()) {
+ if (isa<FieldDecl>(D) || isa<FriendDecl>(D)) {
+ Decl *ToD = Importer.GetAlreadyImportedOrNull(D);
+ assert(ToRD == ToD->getDeclContext());
+ assert(ToRD == ToD->getLexicalDeclContext());
+ assert(!ToRD->containsDecl(ToD));
+ ToRD->addDeclInternal(ToD);
+ }
}
return Error::success();