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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits