[clang] 1a35893 - [clang][ASTImporter] Import typedefs to distinct records as distinct nodes.
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 27 09:00:02 PDT 2023
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);
More information about the cfe-commits
mailing list