aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalázs Kéri <1.int32@gmail.com>2021-12-22 12:11:50 +0100
committerBalázs Kéri <1.int32@gmail.com>2022-02-14 08:27:44 +0100
commit83028ad934d60b024b5b0272cb68523232715dab (patch)
treec80cd68d422c47da4c87bcd8f0554b7fe849ae69
parente59d6dc06313da426e0c624561cf1f18027972b8 (diff)
[clang][AST][ASTImporter] Set record to complete during import of its members.
At import of a member it may require that the record is already set to complete. (For example 'computeDependence' at create of some Expr nodes.) The record at this time may not be completely imported, the result of layout calculations can be incorrect, but at least no crash occurs this way. A good solution would be if fields of every encountered record are imported before other members of all records. This is much more difficult to implement. Differential Revision: https://reviews.llvm.org/D116155
-rw-r--r--clang/lib/AST/ASTImporter.cpp11
-rw-r--r--clang/unittests/AST/ASTImporterTest.cpp54
2 files changed, 63 insertions, 2 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 457465e87d93..063fe2bfdf5e 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2012,6 +2012,14 @@ Error ASTNodeImporter::ImportDefinition(
}
To->startDefinition();
+ // Set the definition to complete even if it is really not complete during
+ // import. Some AST constructs (expressions) require the record layout
+ // to be calculated (see 'clang::computeDependence') at the time they are
+ // constructed. Import of such AST node is possible during import of the
+ // same record, there is no way to have a completely defined record (all
+ // fields imported) at that time without multiple AST import passes.
+ if (!Importer.isMinimalImport())
+ To->setCompleteDefinition(true);
// Complete the definition even if error is returned.
// The RecordDecl may be already part of the AST so it is better to
// have it in complete state even if something is wrong with it.
@@ -2076,9 +2084,10 @@ Error ASTNodeImporter::ImportDefinition(
ToCXX->setBases(Bases.data(), Bases.size());
}
- if (shouldForceImportDeclContext(Kind))
+ if (shouldForceImportDeclContext(Kind)) {
if (Error Err = ImportDeclContext(From, /*ForceImport=*/true))
return Err;
+ }
return Error::success();
}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 04da7988fc30..77c6d6ad2e19 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -6809,7 +6809,8 @@ struct ImportWithExternalSource : ASTImporterOptionSpecificTestBase {
bool MinimalImport,
const std::shared_ptr<ASTImporterSharedState> &SharedState) {
return new ASTImporter(ToContext, ToFileManager, FromContext,
- FromFileManager, MinimalImport,
+ // Use minimal import for these tests.
+ FromFileManager, /*MinimalImport=*/true,
// We use the regular lookup.
/*SharedState=*/nullptr);
};
@@ -7475,6 +7476,57 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuideDifferentOrder) {
ToDGOther);
}
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportRecordWithLayoutRequestingExpr) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ R"(
+ struct A {
+ int idx;
+ static void foo(A x) {
+ (void)&"text"[x.idx];
+ }
+ };
+ )",
+ Lang_CXX11);
+
+ auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+
+ // Test that during import of 'foo' the record layout can be obtained without
+ // crash.
+ auto *ToA = Import(FromA, Lang_CXX11);
+ EXPECT_TRUE(ToA);
+ EXPECT_TRUE(ToA->isCompleteDefinition());
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportRecordWithLayoutRequestingExprDifferentRecord) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ R"(
+ struct B;
+ struct A {
+ int idx;
+ B *b;
+ };
+ struct B {
+ static void foo(A x) {
+ (void)&"text"[x.idx];
+ }
+ };
+ )",
+ Lang_CXX11);
+
+ auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+
+ // Test that during import of 'foo' the record layout (of 'A') can be obtained
+ // without crash. It is not possible to have all of the fields of 'A' imported
+ // at that time (without big code changes).
+ auto *ToA = Import(FromA, Lang_CXX11);
+ EXPECT_TRUE(ToA);
+ EXPECT_TRUE(ToA->isCompleteDefinition());
+}
+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions);