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 @@ -7394,10 +7394,15 @@ if (Err) return std::move(Err); - return UnaryOperator::Create( - Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType, - E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(), - E->getFPOptionsOverride()); + auto *UO = UnaryOperator::CreateEmpty(Importer.getToContext(), + E->hasStoredFPFeatures()); + UO->setType(ToType); + UO->setSubExpr(ToSubExpr); + UO->setOpcode(E->getOpcode()); + UO->setOperatorLoc(ToOperatorLoc); + UO->setCanOverflow(E->canOverflow()); + + return UO; } ExpectedStmt 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 @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/RecordLayout.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" @@ -8028,6 +8029,45 @@ Import(FromF, Lang_CXX11); } +TEST_P(ASTImporterOptionSpecificTestBase, + ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) { + // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ... + // + // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is + // still not completely imported. + auto Code = + R"( + class B; + class A { + B* b; + int c; + }; + class B { + A *f() { return &((B *)0)->a; } + A a; + }; + )"; + + auto *FromR = FirstDeclMatcher().match( + getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A"))); + FromR = FromR->getDefinition(); + auto &FromAST = FromR->getASTContext(); + auto *ToR = Import(FromR, Lang_CXX11); + auto &ToAST = ToR->getASTContext(); + + uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy); + + EXPECT_TRUE(FromR->isCompleteDefinition()); + const auto &FromLayout = FromAST.getASTRecordLayout(FromR); + EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0); + EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset); + + EXPECT_TRUE(ToR->isCompleteDefinition()); + const auto &ToLayout = ToAST.getASTRecordLayout(ToR); + EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0); + EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset); +} + TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordWithLayoutRequestingExpr) { TranslationUnitDecl *FromTU = getTuDecl(