[clang] 1654634 - [clang][ASTImporter] Fix partially import of repeated friend templates
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 23 18:13:07 PDT 2023
Author: dingfei
Date: 2023-08-24T09:10:14+08:00
New Revision: 1654634f6f8bc9a78c6c47f58e4f067fa9a7faef
URL: https://github.com/llvm/llvm-project/commit/1654634f6f8bc9a78c6c47f58e4f067fa9a7faef
DIFF: https://github.com/llvm/llvm-project/commit/1654634f6f8bc9a78c6c47f58e4f067fa9a7faef.diff
LOG: [clang][ASTImporter] Fix partially import of repeated friend templates
Pointer comparison is not reliable in this case. Use ASTStructuralEquivalence
to compute FriendCountAndPosition.
Reviewed By: balazske
Differential Revision: https://reviews.llvm.org/D157684
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 5ef8b6a5c50ee9..77be3b3098cabd 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -4079,22 +4079,34 @@ struct FriendCountAndPosition {
unsigned int IndexOfDecl;
};
-template <class T>
-static FriendCountAndPosition getFriendCountAndPosition(
- const FriendDecl *FD,
- llvm::function_ref<T(const FriendDecl *)> GetCanTypeOrDecl) {
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
+ FriendDecl *FD2) {
+ if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
+ return false;
+
+ if (const TypeSourceInfo *TSI = FD1->getFriendType())
+ return Importer.IsStructurallyEquivalent(
+ TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
+ ASTImporter::NonEquivalentDeclSet NonEquivalentDecls;
+ StructuralEquivalenceContext Ctx(
+ FD1->getASTContext(), FD2->getASTContext(), NonEquivalentDecls,
+ StructuralEquivalenceKind::Default,
+ /* StrictTypeSpelling = */ false, /* Complain = */ false);
+ return Ctx.IsEquivalent(FD1, FD2);
+}
+
+static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
+ FriendDecl *FD) {
unsigned int FriendCount = 0;
std::optional<unsigned int> FriendPosition;
const auto *RD = cast<CXXRecordDecl>(FD->getLexicalDeclContext());
- T TypeOrDecl = GetCanTypeOrDecl(FD);
-
- for (const FriendDecl *FoundFriend : RD->friends()) {
+ for (FriendDecl *FoundFriend : RD->friends()) {
if (FoundFriend == FD) {
FriendPosition = FriendCount;
++FriendCount;
- } else if (!FoundFriend->getFriendDecl() == !FD->getFriendDecl() &&
- GetCanTypeOrDecl(FoundFriend) == TypeOrDecl) {
+ } else if (IsEquivalentFriend(Importer, FD, FoundFriend)) {
++FriendCount;
}
}
@@ -4104,21 +4116,6 @@ static FriendCountAndPosition getFriendCountAndPosition(
return {FriendCount, *FriendPosition};
}
-static FriendCountAndPosition getFriendCountAndPosition(const FriendDecl *FD) {
- if (FD->getFriendType())
- return getFriendCountAndPosition<QualType>(FD, [](const FriendDecl *F) {
- if (TypeSourceInfo *TSI = F->getFriendType())
- return TSI->getType().getCanonicalType();
- llvm_unreachable("Wrong friend object type.");
- });
- else
- return getFriendCountAndPosition<Decl *>(FD, [](const FriendDecl *F) {
- if (Decl *D = F->getFriendDecl())
- return D->getCanonicalDecl();
- llvm_unreachable("Wrong friend object type.");
- });
-}
-
ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
// Import the major distinguishing characteristics of a declaration.
DeclContext *DC, *LexicalDC;
@@ -4129,26 +4126,13 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
// FriendDecl is not a NamedDecl so we cannot use lookup.
// We try to maintain order and count of redundant friend declarations.
const auto *RD = cast<CXXRecordDecl>(DC);
- FriendDecl *ImportedFriend = RD->getFirstFriend();
SmallVector<FriendDecl *, 2> ImportedEquivalentFriends;
-
- while (ImportedFriend) {
- bool Match = false;
- if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) {
- Match =
- IsStructuralMatch(D->getFriendDecl(), ImportedFriend->getFriendDecl(),
- /*Complain=*/false);
- } else if (D->getFriendType() && ImportedFriend->getFriendType()) {
- Match = Importer.IsStructurallyEquivalent(
- D->getFriendType()->getType(),
- ImportedFriend->getFriendType()->getType(), /*Complain=*/false);
- }
- if (Match)
+ for (FriendDecl *ImportedFriend : RD->friends())
+ if (IsEquivalentFriend(Importer, D, ImportedFriend))
ImportedEquivalentFriends.push_back(ImportedFriend);
- ImportedFriend = ImportedFriend->getNextFriend();
- }
- FriendCountAndPosition CountAndPosition = getFriendCountAndPosition(D);
+ FriendCountAndPosition CountAndPosition =
+ getFriendCountAndPosition(Importer, D);
assert(ImportedEquivalentFriends.size() <= CountAndPosition.TotalCount &&
"Class with non-matching friends is imported, ODR check wrong?");
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index ed3703d116a626..a233fd4b6d52b2 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -4054,6 +4054,25 @@ struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
->lookup(ToRecordOfFriend->getDeclName())
.empty());
}
+
+ void testRepeatedFriendImport(const char *Code) {
+ Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
+ Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
+
+ auto *ToFriend1 = FirstDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
+ auto *ToFriend2 = LastDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
+ auto *FromFriend1 =
+ FirstDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
+ auto *FromFriend2 =
+ LastDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
+
+ FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
+ FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+
+ EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
+ EXPECT_EQ(ToFriend1, ToImportedFriend1);
+ EXPECT_EQ(ToFriend2, ToImportedFriend2);
+ }
};
TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
@@ -4395,21 +4414,7 @@ TEST_P(ImportFriendClasses, ImportOfRepeatedFriendType) {
friend class X;
};
)";
- Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
- Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
- auto *ToFriend1 = FirstDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
- auto *ToFriend2 = LastDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
- auto *FromFriend1 =
- FirstDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
- auto *FromFriend2 = LastDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
-
- FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
- FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
-
- EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
- EXPECT_EQ(ToFriend1, ToImportedFriend1);
- EXPECT_EQ(ToFriend2, ToImportedFriend2);
+ testRepeatedFriendImport(Code);
}
TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
@@ -4420,21 +4425,31 @@ TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
friend void f();
};
)";
- Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
- Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
- auto *ToFriend1 = FirstDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
- auto *ToFriend2 = LastDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
- auto *FromFriend1 =
- FirstDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
- auto *FromFriend2 = LastDeclMatcher<FriendDecl>().match(FromTu, friendDecl());
+ testRepeatedFriendImport(Code);
+}
- FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
- FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
+ const char *Code =
+ R"(
+ template <class T>
+ class Container {
+ template <class U> friend void m();
+ template <class U> friend void m();
+ };
+ )";
+ testRepeatedFriendImport(Code);
+}
- EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
- EXPECT_EQ(ToFriend1, ToImportedFriend1);
- EXPECT_EQ(ToFriend2, ToImportedFriend2);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
+ const char *Code =
+ R"(
+ template <class T>
+ class Container {
+ template <class U> friend class X;
+ template <class U> friend class X;
+ };
+ )";
+ testRepeatedFriendImport(Code);
}
TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
More information about the cfe-commits
mailing list