From 83028ad934d60b024b5b0272cb68523232715dab Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bal=C3=A1zs=20K=C3=A9ri?= <1.int32@gmail.com> Date: Wed, 22 Dec 2021 12:11:50 +0100 Subject: [PATCH] [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 --- clang/lib/AST/ASTImporter.cpp | 11 ++++++- clang/unittests/AST/ASTImporterTest.cpp | 54 ++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 457465e..063fe2b 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 04da798..77c6d6a 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 &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().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().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); -- 2.7.4