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())
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);