Skip to content

Commit

Permalink
[ASTImporter] Handle redecl chain of FunctionTemplateDecls
Browse files Browse the repository at this point in the history
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
  • Loading branch information
martong committed Mar 7, 2019
1 parent 27ed855 commit 16d98c2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 50 deletions.
56 changes: 40 additions & 16 deletions clang/lib/AST/ASTImporter.cpp
Expand Up @@ -4943,15 +4943,15 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
return ToD;
}

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

ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Expand Down Expand Up @@ -4983,7 +4983,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (FoundTemplate) {

if (IsStructuralMatch(D, FoundTemplate)) {
ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate);
ClassTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
return Importer.MapImported(D, TemplateWithDef);
}
Expand Down Expand Up @@ -5046,6 +5047,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// and this time the lookup finds the previous fwd friend class template.
// In this case we must set up the previous decl for the templated decl.
if (!ToTemplated->getPreviousDecl()) {
assert(FoundByLookup->getTemplatedDecl() &&
"Found decl must have its templated decl set");
CXXRecordDecl *PrevTemplated =
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
if (ToTemplated != PrevTemplated)
Expand Down Expand Up @@ -5508,27 +5511,33 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (ToD)
return ToD;

const FunctionTemplateDecl *FoundByLookup = nullptr;

// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
// FIXME Split this into a separate function.
if (!LexicalDC->isFunctionOrMethod()) {
unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend;
auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
for (auto *FoundDecl : FoundDecls) {
if (!FoundDecl->isInIdentifierNamespace(IDNS))
continue;

if (auto *FoundFunction =
dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
if (FoundFunction->hasExternalFormalLinkage() &&
if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
if (FoundTemplate->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
if (IsStructuralMatch(D, FoundFunction)) {
Importer.MapImported(D, FoundFunction);
// FIXME: Actually try to merge the body and other attributes.
return FoundFunction;
if (IsStructuralMatch(D, FoundTemplate)) {
FunctionTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && TemplateWithDef) {
return Importer.MapImported(D, TemplateWithDef);
}
FoundByLookup = FoundTemplate;
break;
}
// TODO: handle conflicting names
}
}
// TODO: handle conflicting names
}
}

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

TemplatedFD->setDescribedFunctionTemplate(ToFunc);

ToFunc->setAccess(D->getAccess());
ToFunc->setLexicalDeclContext(LexicalDC);

LexicalDC->addDeclInternal(ToFunc);

if (FoundByLookup) {
auto *Recent =
const_cast<FunctionTemplateDecl *>(FoundByLookup->getMostRecentDecl());
if (!TemplatedFD->getPreviousDecl()) {
assert(FoundByLookup->getTemplatedDecl() &&
"Found decl must have its templated decl set");
auto *PrevTemplated =
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
if (TemplatedFD != PrevTemplated)
TemplatedFD->setPreviousDecl(PrevTemplated);
}
ToFunc->setPreviousDecl(Recent);
}

return ToFunc;
}

Expand Down
48 changes: 14 additions & 34 deletions clang/unittests/AST/ASTImporterTest.cpp
Expand Up @@ -4197,9 +4197,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, Variable, ,
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, FunctionTemplate, DISABLED_,
RedeclChain, FunctionTemplate, ,
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, ClassTemplate, ,
Expand All @@ -4214,9 +4213,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, Class, , DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, Variable, , DefinitionShouldBeImportedAsADefinition)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, FunctionTemplate, DISABLED_,
RedeclChain, FunctionTemplate, ,
DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, ClassTemplate, , DefinitionShouldBeImportedAsADefinition)
Expand All @@ -4230,9 +4228,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypeAfterImportedPrototype)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeAfterImportedPrototype)
Expand All @@ -4245,9 +4241,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportDefinitionAfterImportedPrototype)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitionAfterImportedPrototype)
Expand All @@ -4260,9 +4254,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypeAfterImportedDefinition)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeAfterImportedDefinition)
Expand All @@ -4274,9 +4266,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypes)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_, ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypes)
// FIXME This does not pass, possible error with Spec import.
Expand All @@ -4289,9 +4280,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportDefinitions)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_, ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitions)
// FIXME This does not pass, possible error with Spec import.
Expand All @@ -4304,9 +4294,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportDefinitionThenPrototype)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitionThenPrototype)
Expand All @@ -4321,9 +4309,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypeThenDefinition)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeThenDefinition)
Expand All @@ -4336,9 +4322,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
WholeRedeclChainIsImportedAtOnce)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
WholeRedeclChainIsImportedAtOnce)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
WholeRedeclChainIsImportedAtOnce)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
WholeRedeclChainIsImportedAtOnce)
Expand All @@ -4347,9 +4331,7 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
ImportPrototypeThenProtoAndDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypeThenProtoAndDefinition)
// FIXME Enable this test, once we import function templates chains correctly.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate,
DISABLED_,
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeThenProtoAndDefinition)
// FIXME This does not pass, possible error with Spec import.
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec,
Expand Down Expand Up @@ -5442,9 +5424,7 @@ TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) {
FromTU, functionTemplateDecl(hasName("foo")));
auto *Imported = Import(FromFoo, Lang_CXX);

// FIXME Currently chains of FunctionTemplateDecls are not implemented.
//EXPECT_EQ(Imported->getPreviousDecl(), Friend);
EXPECT_EQ(Imported, Friend);
EXPECT_EQ(Imported->getPreviousDecl(), Friend);
}

INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
Expand Down

0 comments on commit 16d98c2

Please sign in to comment.