Skip to content

Commit 16d98c2

Browse files
committed
[ASTImporter] Handle redecl chain of FunctionTemplateDecls
Summary: Redecl chains of function templates are not handled well currently. We want to handle them similarly to functions, i.e. try to keep the structure of the original AST as much as possible. The aim is to not squash a prototype with a definition, rather we create both and put them in a redecl chain. Reviewers: a_sidorin, shafik, a.sidorin Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D58494 llvm-svn: 355593
1 parent 27ed855 commit 16d98c2

File tree

2 files changed

+54
-50
lines changed

2 files changed

+54
-50
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4943,15 +4943,15 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
49434943
return ToD;
49444944
}
49454945

4946-
// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if
4946+
// Returns the definition for a (forward) declaration of a TemplateDecl, if
49474947
// it has any definition in the redecl chain.
4948-
static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) {
4949-
CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition();
4948+
template <typename T> static auto getTemplateDefinition(T *D) -> T * {
4949+
assert(D->getTemplatedDecl() && "Should be called on templates only");
4950+
auto *ToTemplatedDef = D->getTemplatedDecl()->getDefinition();
49504951
if (!ToTemplatedDef)
49514952
return nullptr;
4952-
ClassTemplateDecl *TemplateWithDef =
4953-
ToTemplatedDef->getDescribedClassTemplate();
4954-
return TemplateWithDef;
4953+
auto *TemplateWithDef = ToTemplatedDef->getDescribedTemplate();
4954+
return cast_or_null<T>(TemplateWithDef);
49554955
}
49564956

49574957
ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
@@ -4983,7 +4983,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
49834983
if (FoundTemplate) {
49844984

49854985
if (IsStructuralMatch(D, FoundTemplate)) {
4986-
ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate);
4986+
ClassTemplateDecl *TemplateWithDef =
4987+
getTemplateDefinition(FoundTemplate);
49874988
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
49884989
return Importer.MapImported(D, TemplateWithDef);
49894990
}
@@ -5046,6 +5047,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
50465047
// and this time the lookup finds the previous fwd friend class template.
50475048
// In this case we must set up the previous decl for the templated decl.
50485049
if (!ToTemplated->getPreviousDecl()) {
5050+
assert(FoundByLookup->getTemplatedDecl() &&
5051+
"Found decl must have its templated decl set");
50495052
CXXRecordDecl *PrevTemplated =
50505053
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
50515054
if (ToTemplated != PrevTemplated)
@@ -5508,27 +5511,33 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
55085511
if (ToD)
55095512
return ToD;
55105513

5514+
const FunctionTemplateDecl *FoundByLookup = nullptr;
5515+
55115516
// Try to find a function in our own ("to") context with the same name, same
55125517
// type, and in the same context as the function we're importing.
5518+
// FIXME Split this into a separate function.
55135519
if (!LexicalDC->isFunctionOrMethod()) {
55145520
unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend;
55155521
auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
55165522
for (auto *FoundDecl : FoundDecls) {
55175523
if (!FoundDecl->isInIdentifierNamespace(IDNS))
55185524
continue;
55195525

5520-
if (auto *FoundFunction =
5521-
dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
5522-
if (FoundFunction->hasExternalFormalLinkage() &&
5526+
if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
5527+
if (FoundTemplate->hasExternalFormalLinkage() &&
55235528
D->hasExternalFormalLinkage()) {
5524-
if (IsStructuralMatch(D, FoundFunction)) {
5525-
Importer.MapImported(D, FoundFunction);
5526-
// FIXME: Actually try to merge the body and other attributes.
5527-
return FoundFunction;
5529+
if (IsStructuralMatch(D, FoundTemplate)) {
5530+
FunctionTemplateDecl *TemplateWithDef =
5531+
getTemplateDefinition(FoundTemplate);
5532+
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
5533+
return Importer.MapImported(D, TemplateWithDef);
5534+
}
5535+
FoundByLookup = FoundTemplate;
5536+
break;
55285537
}
5538+
// TODO: handle conflicting names
55295539
}
55305540
}
5531-
// TODO: handle conflicting names
55325541
}
55335542
}
55345543

@@ -5547,10 +5556,25 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
55475556
return ToFunc;
55485557

55495558
TemplatedFD->setDescribedFunctionTemplate(ToFunc);
5559+
55505560
ToFunc->setAccess(D->getAccess());
55515561
ToFunc->setLexicalDeclContext(LexicalDC);
5552-
55535562
LexicalDC->addDeclInternal(ToFunc);
5563+
5564+
if (FoundByLookup) {
5565+
auto *Recent =
5566+
const_cast<FunctionTemplateDecl *>(FoundByLookup->getMostRecentDecl());
5567+
if (!TemplatedFD->getPreviousDecl()) {
5568+
assert(FoundByLookup->getTemplatedDecl() &&
5569+
"Found decl must have its templated decl set");
5570+
auto *PrevTemplated =
5571+
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
5572+
if (TemplatedFD != PrevTemplated)
5573+
TemplatedFD->setPreviousDecl(PrevTemplated);
5574+
}
5575+
ToFunc->setPreviousDecl(Recent);
5576+
}
5577+
55545578
return ToFunc;
55555579
}
55565580

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4197,9 +4197,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
41974197
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
41984198
RedeclChain, Variable, ,
41994199
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
4200-
// FIXME Enable this test, once we import function templates chains correctly.
42014200
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
4202-
RedeclChain, FunctionTemplate, DISABLED_,
4201+
RedeclChain, FunctionTemplate, ,
42034202
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
42044203
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
42054204
RedeclChain, ClassTemplate, ,
@@ -4214,9 +4213,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
42144213
RedeclChain, Class, , DefinitionShouldBeImportedAsADefinition)
42154214
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
42164215
RedeclChain, Variable, , DefinitionShouldBeImportedAsADefinition)
4217-
// FIXME Enable this test, once we import function templates chains correctly.
42184216
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
4219-
RedeclChain, FunctionTemplate, DISABLED_,
4217+
RedeclChain, FunctionTemplate, ,
42204218
DefinitionShouldBeImportedAsADefinition)
42214219
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
42224220
RedeclChain, ClassTemplate, , DefinitionShouldBeImportedAsADefinition)
@@ -4230,9 +4228,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
42304228
ImportPrototypeAfterImportedPrototype)
42314229
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
42324230
ImportPrototypeAfterImportedPrototype)
4233-
// FIXME Enable this test, once we import function templates chains correctly.
4234-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4235-
DISABLED_,
4231+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
42364232
ImportPrototypeAfterImportedPrototype)
42374233
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
42384234
ImportPrototypeAfterImportedPrototype)
@@ -4245,9 +4241,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
42454241
ImportDefinitionAfterImportedPrototype)
42464242
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
42474243
ImportDefinitionAfterImportedPrototype)
4248-
// FIXME Enable this test, once we import function templates chains correctly.
4249-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4250-
DISABLED_,
4244+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
42514245
ImportDefinitionAfterImportedPrototype)
42524246
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
42534247
ImportDefinitionAfterImportedPrototype)
@@ -4260,9 +4254,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
42604254
ImportPrototypeAfterImportedDefinition)
42614255
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
42624256
ImportPrototypeAfterImportedDefinition)
4263-
// FIXME Enable this test, once we import function templates chains correctly.
4264-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4265-
DISABLED_,
4257+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
42664258
ImportPrototypeAfterImportedDefinition)
42674259
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
42684260
ImportPrototypeAfterImportedDefinition)
@@ -4274,9 +4266,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
42744266
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
42754267
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
42764268
ImportPrototypes)
4277-
// FIXME Enable this test, once we import function templates chains correctly.
4278-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4279-
DISABLED_, ImportPrototypes)
4269+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
4270+
ImportPrototypes)
42804271
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
42814272
ImportPrototypes)
42824273
// FIXME This does not pass, possible error with Spec import.
@@ -4289,9 +4280,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
42894280
ImportDefinitions)
42904281
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
42914282
ImportDefinitions)
4292-
// FIXME Enable this test, once we import function templates chains correctly.
4293-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4294-
DISABLED_, ImportDefinitions)
4283+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
4284+
ImportDefinitions)
42954285
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
42964286
ImportDefinitions)
42974287
// FIXME This does not pass, possible error with Spec import.
@@ -4304,9 +4294,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
43044294
ImportDefinitionThenPrototype)
43054295
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
43064296
ImportDefinitionThenPrototype)
4307-
// FIXME Enable this test, once we import function templates chains correctly.
4308-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4309-
DISABLED_,
4297+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
43104298
ImportDefinitionThenPrototype)
43114299
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
43124300
ImportDefinitionThenPrototype)
@@ -4321,9 +4309,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
43214309
ImportPrototypeThenDefinition)
43224310
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
43234311
ImportPrototypeThenDefinition)
4324-
// FIXME Enable this test, once we import function templates chains correctly.
4325-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4326-
DISABLED_,
4312+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
43274313
ImportPrototypeThenDefinition)
43284314
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
43294315
ImportPrototypeThenDefinition)
@@ -4336,9 +4322,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
43364322
WholeRedeclChainIsImportedAtOnce)
43374323
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
43384324
WholeRedeclChainIsImportedAtOnce)
4339-
// FIXME Enable this test, once we import function templates chains correctly.
4340-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4341-
DISABLED_,
4325+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
43424326
WholeRedeclChainIsImportedAtOnce)
43434327
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
43444328
WholeRedeclChainIsImportedAtOnce)
@@ -4347,9 +4331,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
43474331
ImportPrototypeThenProtoAndDefinition)
43484332
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
43494333
ImportPrototypeThenProtoAndDefinition)
4350-
// FIXME Enable this test, once we import function templates chains correctly.
4351-
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
4352-
DISABLED_,
4334+
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
43534335
ImportPrototypeThenProtoAndDefinition)
43544336
// FIXME This does not pass, possible error with Spec import.
43554337
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec,
@@ -5442,9 +5424,7 @@ TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) {
54425424
FromTU, functionTemplateDecl(hasName("foo")));
54435425
auto *Imported = Import(FromFoo, Lang_CXX);
54445426

5445-
// FIXME Currently chains of FunctionTemplateDecls are not implemented.
5446-
//EXPECT_EQ(Imported->getPreviousDecl(), Friend);
5447-
EXPECT_EQ(Imported, Friend);
5427+
EXPECT_EQ(Imported->getPreviousDecl(), Friend);
54485428
}
54495429

54505430
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,

0 commit comments

Comments
 (0)