Author: Balázs Kéri Date: 2023-03-27T17:58:32+02:00 New Revision: 1a35893d2a58fdead33ec7daa9f1fe53f4787614
URL: https://github.com/llvm/llvm-project/commit/1a35893d2a58fdead33ec7daa9f1fe53f4787614 DIFF: https://github.com/llvm/llvm-project/commit/1a35893d2a58fdead33ec7daa9f1fe53f4787614.diff LOG: [clang][ASTImporter] Import typedefs to distinct records as distinct nodes. When a typedef node is imported, ASTImporter should not find an existing similar typedef node for it that comes from different context (translation unit or scope). This should avoid a situation where an existing typedef declaration is returned at import of a typedef, but the underlying type was already imported as a new type object. Reviewed By: vabridgers Differential Revision: https://reviews.llvm.org/D145479 Added: Modified: clang/lib/AST/ASTImporter.cpp clang/unittests/AST/ASTImporterTest.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index d0da2dae3aa23..db6ebbb8992b7 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2509,6 +2509,22 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { QualType FromUT = D->getUnderlyingType(); QualType FoundUT = FoundTypedef->getUnderlyingType(); if (Importer.IsStructurallyEquivalent(FromUT, FoundUT)) { + // If the underlying declarations are unnamed records these can be + // imported as diff erent types. We should create a distinct typedef + // node in this case. + // If we found an existing underlying type with a record in a + // diff erent context (than the imported), this is already reason for + // having distinct typedef nodes for these. + // Again this can create situation like + // 'typedef int T; typedef int T;' but this is hard to avoid without + // a rename strategy at import. + if (!FromUT.isNull() && !FoundUT.isNull()) { + RecordDecl *FromR = FromUT->getAsRecordDecl(); + RecordDecl *FoundR = FoundUT->getAsRecordDecl(); + if (FromR && FoundR && + !hasSameVisibilityContextAndLinkage(FoundR, FromR)) + continue; + } // If the "From" context has a complete underlying type but we // already have a complete underlying type then return with that. if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType()) diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 95ff850860300..ebdb81b98734a 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -8501,6 +8501,81 @@ TEST_P(ASTImporterOptionSpecificTestBase, EXPECT_EQ(true, FD->hasAttr<NoUniqueAddressAttr>()); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingTypedefToRecord) { + const char *Code = + R"( + struct S { int i; }; + typedef struct S T; + extern T x; + )"; + Decl *ToTU = getToTuDecl(Code, Lang_C99); + Decl *FromTU = getTuDecl(Code, Lang_C99); + + auto *FromX = + FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("x"))); + auto *ToX = Import(FromX, Lang_C99); + EXPECT_TRUE(ToX); + + auto *Typedef1 = + FirstDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T"))); + auto *Typedef2 = + LastDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T"))); + EXPECT_EQ(Typedef1, Typedef2); +} + +TEST_P(ASTImporterOptionSpecificTestBase, + ImportExistingTypedefToUnnamedRecord) { + const char *Code = + R"( + typedef const struct { int f; } T; + extern T x; + )"; + Decl *ToTU = getToTuDecl(Code, Lang_C99); + Decl *FromTU = getTuDecl(Code, Lang_C99); + + auto *FromX = + FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("x"))); + auto *ToX = Import(FromX, Lang_C99); + EXPECT_TRUE(ToX); + + auto *Typedef1 = + FirstDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T"))); + auto *Typedef2 = + LastDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T"))); + EXPECT_NE(Typedef1, Typedef2); + EXPECT_NE(Typedef1->getUnderlyingType().getTypePtr(), + Typedef2->getUnderlyingType().getTypePtr()); + EXPECT_EQ(ToX->getType()->getAs<TypedefType>()->getDecl(), Typedef2); +} + +TEST_P(ASTImporterOptionSpecificTestBase, ImportTwoTypedefsToUnnamedRecord) { + const char *Code = + R"( + typedef struct { int f; } T1; + typedef struct { int f; } T2; + extern T1 x1; + extern T2 x2; + )"; + Decl *ToTU = getToTuDecl("", Lang_C99); + Decl *FromTU = getTuDecl(Code, Lang_C99); + + auto *FromX1 = + FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("x1"))); + auto *FromX2 = + FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("x2"))); + auto *ToX1 = Import(FromX1, Lang_C99); + EXPECT_TRUE(ToX1); + auto *ToX2 = Import(FromX2, Lang_C99); + EXPECT_TRUE(ToX2); + + auto *Typedef1 = + FirstDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T1"))); + auto *Typedef2 = + FirstDeclMatcher<TypedefDecl>().match(ToTU, typedefDecl(hasName("T2"))); + EXPECT_NE(Typedef1->getUnderlyingType().getTypePtr(), + Typedef2->getUnderlyingType().getTypePtr()); +} + INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits