[ASTImporter] Improved variable template redecl chain handling.

Reviewers: martong, a.sidorin, shafik

Reviewed By: martong

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, teemperor, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74720
This commit is contained in:
Balázs Kéri 2020-02-25 14:47:38 +01:00
parent e0568ef2c5
commit 7b6168e7be
2 changed files with 72 additions and 20 deletions

View File

@ -3881,6 +3881,13 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
ToVar->setPreviousDecl(Recent);
}
// Import the described template, if any.
if (D->getDescribedVarTemplate()) {
auto ToVTOrErr = import(D->getDescribedVarTemplate());
if (!ToVTOrErr)
return ToVTOrErr.takeError();
}
if (Error Err = ImportInitializer(D, ToVar))
return std::move(Err);
@ -5460,20 +5467,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
// If this variable has a definition in the translation unit we're coming
// from,
// but this particular declaration is not that definition, import the
// definition and map to that.
auto *Definition =
cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition());
if (Definition && Definition != D->getTemplatedDecl()) {
if (ExpectedDecl ImportedDefOrErr = import(
Definition->getDescribedVarTemplate()))
return Importer.MapImported(D, *ImportedDefOrErr);
else
return ImportedDefOrErr.takeError();
}
// Import the major distinguishing characteristics of this variable template.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@ -5487,19 +5480,26 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
// We may already have a template of the same name; try to find and match it.
assert(!DC->isFunctionOrMethod() &&
"Variable templates cannot be declared at function scope");
SmallVector<NamedDecl *, 4> ConflictingDecls;
auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
VarTemplateDecl *FoundByLookup = nullptr;
for (auto *FoundDecl : FoundDecls) {
if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
continue;
Decl *Found = FoundDecl;
if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) {
if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(FoundDecl)) {
if (IsStructuralMatch(D, FoundTemplate)) {
// The variable templates structurally match; call it the same template.
Importer.MapImported(D->getTemplatedDecl(),
FoundTemplate->getTemplatedDecl());
return Importer.MapImported(D, FoundTemplate);
// The Decl in the "From" context has a definition, but in the
// "To" context we already have a definition.
VarTemplateDecl *FoundDef = getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && FoundDef)
// FIXME Check for ODR error if the two definitions have
// different initializers?
return Importer.MapImported(D, FoundDef);
FoundByLookup = FoundTemplate;
break;
}
ConflictingDecls.push_back(FoundDecl);
}
@ -5544,6 +5544,18 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
ToVarTD->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToVarTD);
if (FoundByLookup) {
auto *Recent =
const_cast<VarTemplateDecl *>(FoundByLookup->getMostRecentDecl());
if (!ToTemplated->getPreviousDecl()) {
auto *PrevTemplated =
FoundByLookup->getTemplatedDecl()->getMostRecentDecl();
if (ToTemplated != PrevTemplated)
ToTemplated->setPreviousDecl(PrevTemplated);
}
ToVarTD->setPreviousDecl(Recent);
}
if (DTemplated->isThisDeclarationADefinition() &&
!ToTemplated->isThisDeclarationADefinition()) {
// FIXME: Import definition!

View File

@ -74,6 +74,21 @@ struct ClassTemplate {
}
};
struct VariableTemplate {
using DeclTy = VarTemplateDecl;
static constexpr auto *Prototype = "template <class T> extern T X;";
static constexpr auto *Definition =
R"(
template <class T> T X;
template <> int X<int>;
)";
// There is no matcher for varTemplateDecl so use a work-around.
BindableMatcher<Decl> getPattern() {
return namedDecl(hasName("X"), unless(isImplicit()),
has(templateTypeParmDecl()));
}
};
struct FunctionTemplateSpec {
using DeclTy = FunctionDecl;
static constexpr auto *Prototype =
@ -427,6 +442,9 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, ClassTemplate, ,
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, VariableTemplate, ,
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
RedeclChain, FunctionTemplateSpec, ,
PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
@ -446,6 +464,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
DefinitionShouldBeImportedAsADefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -463,6 +483,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportPrototypeAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -480,6 +502,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportDefinitionAfterImportedPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -497,6 +521,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportPrototypeAfterImportedDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -513,6 +539,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
ImportPrototypes)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
@ -529,6 +557,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
ImportDefinitions)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
@ -546,6 +576,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportDefinitionThenPrototype)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -563,6 +595,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportPrototypeThenDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
@ -574,6 +608,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
WholeRedeclChainIsImportedAtOnce)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
WholeRedeclChainIsImportedAtOnce)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
WholeRedeclChainIsImportedAtOnce)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
WholeRedeclChainIsImportedAtOnce)
@ -583,6 +619,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
ImportPrototypeThenProtoAndDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
ImportPrototypeThenProtoAndDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, VariableTemplate, ,
ImportPrototypeThenProtoAndDefinition)
ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
ImportPrototypeThenProtoAndDefinition)
@ -598,6 +636,8 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplate,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariableTemplate,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplateSpec,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplateSpec,