Skip to content

Commit 7be501c

Browse files
authored
[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.)
1 parent 98e747b commit 7be501c

File tree

2 files changed

+119
-2
lines changed

2 files changed

+119
-2
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
60936093
Decl::IDNS_TagFriend))
60946094
continue;
60956095

6096-
Decl *Found = FoundDecl;
6097-
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
6096+
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
60986097
if (FoundTemplate) {
60996098
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
61006099
continue;
@@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
61186117
// see ASTTests test ImportExistingFriendClassTemplateDef.
61196118
continue;
61206119
}
6120+
// When importing a friend, it is possible that multiple declarations
6121+
// with same name can co-exist in specific cases (if a template contains
6122+
// a friend template and has a specialization). For this case the
6123+
// declarations should match, except that the "template depth" is
6124+
// different. No linking of previous declaration is needed in this case.
6125+
// FIXME: This condition may need refinement.
6126+
if (D->getFriendObjectKind() != Decl::FOK_None &&
6127+
FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
6128+
D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
6129+
IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
6130+
/*IgnoreTemplateParmDepth=*/true))
6131+
continue;
6132+
61216133
ConflictingDecls.push_back(FoundDecl);
61226134
}
61236135
}

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10181,6 +10181,111 @@ TEST_P(ImportTemplateParmDeclDefaultValue,
1018110181
FromD, FromDInherited);
1018210182
}
1018310183

10184+
TEST_P(ASTImporterOptionSpecificTestBase,
10185+
ExistingUndeclaredImportDeclaredFriend) {
10186+
Decl *ToTU = getToTuDecl(
10187+
R"(
10188+
template <class A, A>
10189+
struct foo;
10190+
10191+
template <class A>
10192+
struct X {
10193+
template <class A1, A1>
10194+
friend struct foo;
10195+
};
10196+
)",
10197+
Lang_CXX11);
10198+
Decl *FromTU = getTuDecl(
10199+
R"(
10200+
template <class A, A>
10201+
struct foo;
10202+
10203+
template <class A>
10204+
struct X {
10205+
template <class A1, A1>
10206+
friend struct foo;
10207+
};
10208+
10209+
X<int> x;
10210+
)",
10211+
Lang_CXX11);
10212+
10213+
auto *ToFr1 = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
10214+
auto *ToFrD1 = ToFr1->getFriendDecl();
10215+
10216+
auto *FromFr1 = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
10217+
auto *FromFr2 = LastDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
10218+
10219+
auto *FromFrD1 = FromFr1->getFriendDecl();
10220+
auto *FromFrD2 = FromFr2->getFriendDecl();
10221+
10222+
auto *Ctx1 = cast<Decl>(FromFrD1->getDeclContext());
10223+
auto *Ctx2 = cast<Decl>(FromFrD2->getDeclContext());
10224+
10225+
ASSERT_EQ(Ctx1, Ctx2);
10226+
ASSERT_EQ(ToFrD1->getTemplateDepth(), 1u);
10227+
ASSERT_EQ(FromFrD2->getTemplateDepth(), 0u);
10228+
ASSERT_EQ(ToFrD1->getFriendObjectKind(), Decl::FOK_Undeclared);
10229+
ASSERT_EQ(FromFrD2->getFriendObjectKind(), Decl::FOK_Declared);
10230+
10231+
auto *ToFr2Imp = Import(FromFr2, Lang_CXX11);
10232+
10233+
EXPECT_TRUE(ToFr2Imp);
10234+
}
10235+
10236+
TEST_P(ASTImporterOptionSpecificTestBase,
10237+
ExistingDeclaredImportUndeclaredFriend) {
10238+
Decl *ToTU = getToTuDecl(
10239+
R"(
10240+
template <class A, A>
10241+
struct foo;
10242+
10243+
template <class A>
10244+
struct X {
10245+
template <class A1, A1>
10246+
friend struct foo;
10247+
};
10248+
10249+
X<int> x;
10250+
)",
10251+
Lang_CXX11);
10252+
Decl *FromTU = getTuDecl(
10253+
R"(
10254+
template <class A, A>
10255+
struct foo;
10256+
10257+
template <class A>
10258+
struct X {
10259+
template <class A1, A1>
10260+
friend struct foo;
10261+
};
10262+
)",
10263+
Lang_CXX11);
10264+
10265+
auto *ToFr1 = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
10266+
auto *ToFr2 = LastDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
10267+
10268+
auto *ToFrD1 = ToFr1->getFriendDecl();
10269+
auto *ToFrD2 = ToFr2->getFriendDecl();
10270+
10271+
auto *FromFr1 = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
10272+
auto *FromFrD1 = FromFr1->getFriendDecl();
10273+
10274+
auto *Ctx1 = cast<Decl>(ToFrD1->getDeclContext());
10275+
auto *Ctx2 = cast<Decl>(ToFrD2->getDeclContext());
10276+
10277+
ASSERT_EQ(Ctx1, Ctx2);
10278+
ASSERT_EQ(FromFrD1->getTemplateDepth(), 1u);
10279+
ASSERT_EQ(ToFrD2->getTemplateDepth(), 0u);
10280+
ASSERT_EQ(FromFrD1->getFriendObjectKind(), Decl::FOK_Undeclared);
10281+
ASSERT_EQ(ToFrD2->getFriendObjectKind(), Decl::FOK_Declared);
10282+
10283+
auto *ToFr1Imp = Import(FromFr1, Lang_CXX11);
10284+
10285+
EXPECT_TRUE(ToFr1Imp);
10286+
EXPECT_EQ(ToFr1Imp, ToFr1);
10287+
}
10288+
1018410289
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
1018510290
DefaultTestValuesForRunOptions);
1018610291

0 commit comments

Comments
 (0)