summaryrefslogtreecommitdiffstats
path: root/lib/Sema
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-03 23:51:38 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-03 23:51:38 +0000
commit6cc60c9164a96f1d73ccfd302303490e0d085b87 (patch)
treef2639ec1876eaba545ef3845d3572424ae9cc621 /lib/Sema
parentdb45e9b8b840d510c5c5bc1bf7476e70312c59dd (diff)
CWG issue 727: Fix numerous bugs in support for class-scope explicit
specializations for variable templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359947 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--lib/Sema/SemaTemplate.cpp9
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp181
3 files changed, 108 insertions, 97 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9564c8f0cb..2d9dbdd342 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -15721,7 +15721,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ if (Var->isInvalidDecl())
+ return;
+
+ auto *MSI = Var->getMemberSpecializationInfo();
+ TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind()
+ : Var->getTemplateSpecializationKind();
bool OdrUseContext = isOdrUseContext(SemaRef);
bool UsableInConstantExpr =
@@ -15754,11 +15759,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
(TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
if (TryInstantiating) {
- SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
+ SourceLocation PointOfInstantiation =
+ MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
- Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ if (MSI)
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ else
+ Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
bool InstantiationDependent = false;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 939941a4c2..58ad439747 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3927,13 +3927,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization->setAccess(VarTemplate->getAccess());
}
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Specialization->isStaticDataMember())
- Specialization->setInstantiationOfStaticDataMember(
- VarTemplate->getTemplatedDecl(),
- Specialization->getSpecializationKind());
-
return Specialization;
}
@@ -9198,7 +9191,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!PrevTemplate) {
if (!Prev || !Prev->isStaticDataMember()) {
- // We expect to see a data data member here.
+ // We expect to see a static data member here.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
<< Name;
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 90ae8989c1..653eb69326 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3132,13 +3132,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
"for a member class template");
// Lookup the already-instantiated declaration in the instantiation
- // of the class template. FIXME: Diagnose or assert if this fails?
- DeclContext::lookup_result Found
- = Owner->lookup(ClassTemplate->getDeclName());
- if (Found.empty())
- return nullptr;
- ClassTemplateDecl *InstClassTemplate
- = dyn_cast<ClassTemplateDecl>(Found.front());
+ // of the class template.
+ ClassTemplateDecl *InstClassTemplate =
+ cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), ClassTemplate, TemplateArgs));
if (!InstClassTemplate)
return nullptr;
@@ -3247,6 +3244,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Instantiate the members of the class-scope explicit specialization eagerly.
// We don't have support for lazy instantiation of an explicit specialization
// yet, and MSVC eagerly instantiates in this case.
+ // FIXME: This is wrong in standard C++.
if (D->isThisDeclarationADefinition() &&
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
TSK_ImplicitInstantiation,
@@ -3264,6 +3262,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
assert(VarTemplate &&
"A template specialization without specialized template?");
+ VarTemplateDecl *InstVarTemplate =
+ cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), VarTemplate, TemplateArgs));
+ if (!InstVarTemplate)
+ return nullptr;
+
// Substitute the current template arguments.
const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
@@ -3275,28 +3279,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(
- VarTemplate, VarTemplate->getBeginLoc(),
- const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
- Converted))
+ if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
+ VarTemplateArgsInfo, false, Converted))
return nullptr;
- // Find the variable template specialization declaration that
- // corresponds to these arguments.
+ // Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
- Converted, InsertPos))
- // If we already have a variable template specialization, return it.
- return VarSpec;
+ VarTemplateSpecializationDecl *PrevDecl =
+ InstVarTemplate->findSpecialization(Converted, InsertPos);
+
+ // Check whether we've already seen a conflicting instantiation of this
+ // declaration (for instance, if there was a prior implicit instantiation).
+ bool Ignored;
+ if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl(
+ D->getLocation(), D->getSpecializationKind(), PrevDecl,
+ PrevDecl->getSpecializationKind(),
+ PrevDecl->getPointOfInstantiation(), Ignored))
+ return nullptr;
- return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
- VarTemplateArgsInfo, Converted);
+ return VisitVarTemplateSpecializationDecl(
+ InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- ArrayRef<TemplateArgument> Converted) {
+ ArrayRef<TemplateArgument> Converted,
+ VarTemplateSpecializationDecl *PrevDecl) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
@@ -3323,8 +3332,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (SubstQualifier(D, Var))
return nullptr;
- SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
- Owner, StartingScope);
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
+ StartingScope, false, PrevDecl);
return Var;
}
@@ -4339,7 +4348,19 @@ void Sema::BuildVariableInstantiation(
const MultiLevelTemplateArgumentList &TemplateArgs,
LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
LocalInstantiationScope *StartingScope,
- bool InstantiatingVarTemplate) {
+ bool InstantiatingVarTemplate,
+ VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) {
+ // Instantiating a partial specialization to produce a partial
+ // specialization.
+ bool InstantiatingVarTemplatePartialSpec =
+ isa<VarTemplatePartialSpecializationDecl>(OldVar) &&
+ isa<VarTemplatePartialSpecializationDecl>(NewVar);
+ // Instantiating from a variable template (or partial specialization) to
+ // produce a variable template specialization.
+ bool InstantiatingSpecFromTemplate =
+ isa<VarTemplateSpecializationDecl>(NewVar) &&
+ (OldVar->getDescribedVarTemplate() ||
+ isa<VarTemplatePartialSpecializationDecl>(OldVar));
// If we are instantiating a local extern declaration, the
// instantiation belongs lexically to the containing function.
@@ -4385,8 +4406,11 @@ void Sema::BuildVariableInstantiation(
NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs))
Previous.addDecl(NewPrev);
} else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
- OldVar->hasLinkage())
+ OldVar->hasLinkage()) {
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
+ } else if (PrevDeclForVarTemplateSpecialization) {
+ Previous.addDecl(PrevDeclForVarTemplateSpecialization);
+ }
CheckVariableDeclaration(NewVar, Previous);
if (!InstantiatingVarTemplate) {
@@ -4402,23 +4426,44 @@ void Sema::BuildVariableInstantiation(
// Link instantiations of static data members back to the template from
// which they were instantiated.
- if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate)
+ //
+ // Don't do this when instantiating a template (we link the template itself
+ // back in that case) nor when instantiating a static data member template
+ // (that's not a member specialization).
+ if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate &&
+ !InstantiatingSpecFromTemplate)
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
+ // If the pattern is an (in-class) explicit specialization, then the result
+ // is also an explicit specialization.
+ if (VarTemplateSpecializationDecl *OldVTSD =
+ dyn_cast<VarTemplateSpecializationDecl>(OldVar)) {
+ if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(OldVTSD))
+ cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind(
+ TSK_ExplicitSpecialization);
+ }
+
// Forward the mangling number from the template to the instantiated decl.
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
- // Delay instantiation of the initializer for variable templates or inline
- // static data members until a definition of the variable is needed. We need
- // it right away if the type contains 'auto'.
- if ((!isa<VarTemplateSpecializationDecl>(NewVar) &&
- !InstantiatingVarTemplate &&
- !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
- !NewVar->isThisDeclarationADefinition())) ||
- NewVar->getType()->isUndeducedType())
+ // Figure out whether to eagerly instantiate the initializer.
+ if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
+ // We're producing a template. Don't instantiate the initializer yet.
+ } else if (NewVar->getType()->isUndeducedType()) {
+ // We need the type to complete the declaration of the variable.
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ } else if (InstantiatingSpecFromTemplate ||
+ (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
+ !NewVar->isThisDeclarationADefinition())) {
+ // Delay instantiation of the initializer for variable template
+ // specializations or inline static data members until a definition of the
+ // variable is needed.
+ } else {
+ InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ }
// Diagnose unused local variables with dependent types, where the diagnostic
// will have been deferred.
@@ -4518,15 +4563,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
if (Var->isInvalidDecl())
return;
- VarTemplateSpecializationDecl *VarSpec =
- dyn_cast<VarTemplateSpecializationDecl>(Var);
- VarDecl *PatternDecl = nullptr, *Def = nullptr;
+ // Never instantiate an explicitly-specialized entity.
+ TemplateSpecializationKind TSK =
+ Var->getTemplateSpecializationKindForInstantiation();
+ if (TSK == TSK_ExplicitSpecialization)
+ return;
+
+ // Find the pattern and the arguments to substitute into it.
+ VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
+ assert(PatternDecl && "no pattern for templated variable");
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
if (VarSpec) {
// If this is a variable template specialization, make sure that it is
- // non-dependent, then find its instantiation pattern.
+ // non-dependent.
bool InstantiationDependent = false;
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
@@ -4534,37 +4587,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
"not type-dependent");
(void)InstantiationDependent;
- // Find the variable initialization that we'll be substituting. If the
- // pattern was instantiated from a member template, look back further to
- // find the real pattern.
- assert(VarSpec->getSpecializedTemplate() &&
- "Specialization without specialized template?");
- llvm::PointerUnion<VarTemplateDecl *,
- VarTemplatePartialSpecializationDecl *> PatternPtr =
- VarSpec->getSpecializedTemplateOrPartial();
- if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
- VarTemplatePartialSpecializationDecl *Tmpl =
- PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
- while (VarTemplatePartialSpecializationDecl *From =
- Tmpl->getInstantiatedFromMember()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl;
- } else {
- VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
- while (VarTemplateDecl *From =
- Tmpl->getInstantiatedFromMemberTemplate()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl->getTemplatedDecl();
- }
-
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
@@ -4608,20 +4630,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Local.Exit();
GlobalInstantiations.perform();
}
-
- // Find actual definition
- Def = PatternDecl->getDefinition(getASTContext());
} else {
- // If this is a static data member, find its out-of-line definition.
- assert(Var->isStaticDataMember() && "not a static data member?");
- PatternDecl = Var->getInstantiatedFromStaticDataMember();
-
- assert(PatternDecl && "data member was not instantiated from a template?");
- assert(PatternDecl->isStaticDataMember() && "not a static data member?");
- Def = PatternDecl->getDefinition();
+ assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() &&
+ "not a static data member?");
}
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ VarDecl *Def = PatternDecl->getDefinition(getASTContext());
// If we don't have a definition of the variable template, we won't perform
// any instantiation. Rather, we rely on the user to instantiate this
@@ -4643,7 +4657,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
}
return;
}
-
}
// FIXME: We need to track the instantiation stack in order to know which
@@ -4655,11 +4668,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
/*Complain*/DefinitionRequired))
return;
-
- // Never instantiate an explicit specialization.
- if (TSK == TSK_ExplicitSpecialization)
- return;
-
// C++11 [temp.explicit]p10:
// Except for inline functions, const variables of literal types, variables
// of reference types, [...] explicit instantiation declarations
@@ -5495,7 +5503,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
- switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) {
+ switch (Var->getMostRecentDecl()
+ ->getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration: