Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit 643c9c2

Browse files
balazskemartong
authored andcommitted
Fix for import of friend class template with definition. (#691)
If there is a friend class template "prototype" (forward declaration) and later a definition for it in the existing code, this existing definition may be not found by ASTImporter because it is not linked to the prototype (under the friend AST node). The problem is fixed by looping over all found matching decls instead of break after the first found one.
1 parent 446c84d commit 643c9c2

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

lib/AST/ASTImporter.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5155,11 +5155,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
51555155
if (isStructuralMatch(D, FoundTemplate)) {
51565156
ClassTemplateDecl *TemplateWithDef =
51575157
getTemplateDefinition(FoundTemplate);
5158-
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
5158+
if (D->isThisDeclarationADefinition() && TemplateWithDef)
51595159
return Importer.MapImported(D, TemplateWithDef);
5160-
}
5161-
FoundByLookup = FoundTemplate;
5162-
break;
5160+
if (!FoundByLookup)
5161+
FoundByLookup = FoundTemplate;
5162+
continue;
51635163
}
51645164
ConflictingDecls.push_back(FoundDecl);
51655165
}

unittests/AST/ASTImporterTest.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5264,6 +5264,50 @@ TEST_P(ASTImporterCImplicitFunctionTest,
52645264
EXPECT_EQ(ToImplicitF->getDefinition(), ToImplicitFDef);
52655265
}
52665266

5267+
TEST_P(ASTImporterOptionSpecificTestBase,
5268+
ImportExistingFriendClassTemplateDef) {
5269+
auto Code =
5270+
R"(
5271+
template <class T1, class T2>
5272+
struct Base {
5273+
template <class U1, class U2>
5274+
friend struct Class;
5275+
};
5276+
template <class T1, class T2>
5277+
struct Class { };
5278+
)";
5279+
5280+
TranslationUnitDecl *ToTU = getToTuDecl(Code, Lang_CXX);
5281+
TranslationUnitDecl *FromTU = getTuDecl(Code, Lang_CXX, "input.cc");
5282+
5283+
auto *ToClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
5284+
ToTU, classTemplateDecl(hasName("Class")));
5285+
auto *ToClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
5286+
ToTU, classTemplateDecl(hasName("Class")));
5287+
ASSERT_FALSE(ToClassProto->isThisDeclarationADefinition());
5288+
ASSERT_TRUE(ToClassDef->isThisDeclarationADefinition());
5289+
// Previous friend decl is not linked to it!
5290+
ASSERT_FALSE(ToClassDef->getPreviousDecl());
5291+
ASSERT_EQ(ToClassDef->getMostRecentDecl(), ToClassDef);
5292+
ASSERT_EQ(ToClassProto->getMostRecentDecl(), ToClassProto);
5293+
5294+
auto *FromClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
5295+
FromTU, classTemplateDecl(hasName("Class")));
5296+
auto *FromClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
5297+
FromTU, classTemplateDecl(hasName("Class")));
5298+
ASSERT_FALSE(FromClassProto->isThisDeclarationADefinition());
5299+
ASSERT_TRUE(FromClassDef->isThisDeclarationADefinition());
5300+
ASSERT_FALSE(FromClassDef->getPreviousDecl());
5301+
ASSERT_EQ(FromClassDef->getMostRecentDecl(), FromClassDef);
5302+
ASSERT_EQ(FromClassProto->getMostRecentDecl(), FromClassProto);
5303+
5304+
auto *ImportedDef = Import(FromClassDef, Lang_CXX);
5305+
// At import we should find the definition for 'Class' even if the
5306+
// prototype (inside 'friend') for it comes first in the AST and is not
5307+
// linked to the definition.
5308+
EXPECT_EQ(ImportedDef, ToClassDef);
5309+
}
5310+
52675311
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterCImplicitFunctionTest,
52685312
DefaultTestValuesForRunOptions, );
52695313

0 commit comments

Comments
 (0)