Skip to content

Commit

Permalink
[clang][ASTImporter] Import typedefs to distinct records as distinct …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
balazske committed Mar 27, 2023
1 parent 0f76fb9 commit 1a35893
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
16 changes: 16 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Expand Up @@ -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 different types. We should create a distinct typedef
// node in this case.
// If we found an existing underlying type with a record in a
// different 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())
Expand Down
75 changes: 75 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Expand Up @@ -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);

Expand Down

0 comments on commit 1a35893

Please sign in to comment.