[clang] 7be501c - [clang][ASTImporter] Allow import of similar friend template with different depth (#115734)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 2 01:08:18 PST 2024
Author: Balázs Kéri
Date: 2024-12-02T10:08:14+01:00
New Revision: 7be501c1d3b3153e08603670873e1b3b700c9598
URL: https://github.com/llvm/llvm-project/commit/7be501c1d3b3153e08603670873e1b3b700c9598
DIFF: https://github.com/llvm/llvm-project/commit/7be501c1d3b3153e08603670873e1b3b700c9598.diff
LOG: [clang][ASTImporter] Allow import of similar friend template with different depth (#115734)
This fix applies to a case that occurs when the AST contains a friend
template that is contained within another template and this (outer)
template has specialization. (See the added test code in the commit.)
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 a0cd57e2e5ee0d..26d33b0d94795f 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl::IDNS_TagFriend))
continue;
- Decl *Found = FoundDecl;
- auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
+ auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
if (FoundTemplate) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
@@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// see ASTTests test ImportExistingFriendClassTemplateDef.
continue;
}
+ // When importing a friend, it is possible that multiple declarations
+ // with same name can co-exist in specific cases (if a template contains
+ // a friend template and has a specialization). For this case the
+ // declarations should match, except that the "template depth" is
+ //
diff erent. No linking of previous declaration is needed in this case.
+ // FIXME: This condition may need refinement.
+ if (D->getFriendObjectKind() != Decl::FOK_None &&
+ FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
+ D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
+ IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
+ /*IgnoreTemplateParmDepth=*/true))
+ continue;
+
ConflictingDecls.push_back(FoundDecl);
}
}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index bf7313f882e455..abf07d094e62c3 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -10181,6 +10181,111 @@ TEST_P(ImportTemplateParmDeclDefaultValue,
FromD, FromDInherited);
}
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ExistingUndeclaredImportDeclaredFriend) {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ template <class A, A>
+ struct foo;
+
+ template <class A>
+ struct X {
+ template <class A1, A1>
+ friend struct foo;
+ };
+ )",
+ Lang_CXX11);
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <class A, A>
+ struct foo;
+
+ template <class A>
+ struct X {
+ template <class A1, A1>
+ friend struct foo;
+ };
+
+ X<int> x;
+ )",
+ Lang_CXX11);
+
+ auto *ToFr1 = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
+ auto *ToFrD1 = ToFr1->getFriendDecl();
+
+ auto *FromFr1 = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
+ auto *FromFr2 = LastDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
+
+ auto *FromFrD1 = FromFr1->getFriendDecl();
+ auto *FromFrD2 = FromFr2->getFriendDecl();
+
+ auto *Ctx1 = cast<Decl>(FromFrD1->getDeclContext());
+ auto *Ctx2 = cast<Decl>(FromFrD2->getDeclContext());
+
+ ASSERT_EQ(Ctx1, Ctx2);
+ ASSERT_EQ(ToFrD1->getTemplateDepth(), 1u);
+ ASSERT_EQ(FromFrD2->getTemplateDepth(), 0u);
+ ASSERT_EQ(ToFrD1->getFriendObjectKind(), Decl::FOK_Undeclared);
+ ASSERT_EQ(FromFrD2->getFriendObjectKind(), Decl::FOK_Declared);
+
+ auto *ToFr2Imp = Import(FromFr2, Lang_CXX11);
+
+ EXPECT_TRUE(ToFr2Imp);
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ExistingDeclaredImportUndeclaredFriend) {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ template <class A, A>
+ struct foo;
+
+ template <class A>
+ struct X {
+ template <class A1, A1>
+ friend struct foo;
+ };
+
+ X<int> x;
+ )",
+ Lang_CXX11);
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <class A, A>
+ struct foo;
+
+ template <class A>
+ struct X {
+ template <class A1, A1>
+ friend struct foo;
+ };
+ )",
+ Lang_CXX11);
+
+ auto *ToFr1 = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
+ auto *ToFr2 = LastDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
+
+ auto *ToFrD1 = ToFr1->getFriendDecl();
+ auto *ToFrD2 = ToFr2->getFriendDecl();
+
+ auto *FromFr1 = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
+ auto *FromFrD1 = FromFr1->getFriendDecl();
+
+ auto *Ctx1 = cast<Decl>(ToFrD1->getDeclContext());
+ auto *Ctx2 = cast<Decl>(ToFrD2->getDeclContext());
+
+ ASSERT_EQ(Ctx1, Ctx2);
+ ASSERT_EQ(FromFrD1->getTemplateDepth(), 1u);
+ ASSERT_EQ(ToFrD2->getTemplateDepth(), 0u);
+ ASSERT_EQ(FromFrD1->getFriendObjectKind(), Decl::FOK_Undeclared);
+ ASSERT_EQ(ToFrD2->getFriendObjectKind(), Decl::FOK_Declared);
+
+ auto *ToFr1Imp = Import(FromFr1, Lang_CXX11);
+
+ EXPECT_TRUE(ToFr1Imp);
+ EXPECT_EQ(ToFr1Imp, ToFr1);
+}
+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions);
More information about the cfe-commits
mailing list