Variable templates: handle instantiation of static data member templates
appropriately, especially when they appear within class templates.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191548 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 62f65a5..ccfbeeb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -8338,7 +8338,8 @@
if (VDecl->getStorageClass() == SC_Extern &&
(!getLangOpts().CPlusPlus ||
!(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
- VDecl->isExternC())))
+ VDecl->isExternC())) &&
+ !isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
// C99 6.7.8p4. All file scoped initializers need to be constant.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a52ebf6..b1a768d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -11767,45 +11767,33 @@
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
+ assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
+ "Can't instantiate a partial template specialization.");
// Implicit instantiation of static data members, static data member
// templates of class templates, and variable template specializations.
// Delay instantiations of variable templates, except for those
// that could be used in a constant expression.
- if (VarSpec || (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember())) {
- MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
- if (VarSpec)
- assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
- "Can't instantiate a partial template specialization.");
- if (Var->isStaticDataMember())
- assert(MSInfo && "Missing member specialization information?");
+ TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ if (isTemplateInstantiation(TSK)) {
+ bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
- SourceLocation PointOfInstantiation;
- bool InstantiationIsOkay = true;
- if (MSInfo) {
- bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
- TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind();
-
- if (TSK == TSK_ImplicitInstantiation &&
- (!AlreadyInstantiated ||
- Var->isUsableInConstantExpressions(SemaRef.Context))) {
- if (!AlreadyInstantiated) {
- // This is a modification of an existing AST node. Notify listeners.
- if (ASTMutationListener *L = SemaRef.getASTMutationListener())
- L->StaticDataMemberInstantiated(Var);
- MSInfo->setPointOfInstantiation(Loc);
- }
- PointOfInstantiation = MSInfo->getPointOfInstantiation();
- } else
- InstantiationIsOkay = false;
- } else {
- if (VarSpec->getPointOfInstantiation().isInvalid())
- VarSpec->setPointOfInstantiation(Loc);
- PointOfInstantiation = VarSpec->getPointOfInstantiation();
+ if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
+ if (Var->getPointOfInstantiation().isInvalid()) {
+ // This is a modification of an existing AST node. Notify listeners.
+ if (ASTMutationListener *L = SemaRef.getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
+ } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
+ // Don't bother trying to instantiate it again, unless we might need
+ // its initializer before we get to the end of the TU.
+ TryInstantiating = false;
}
- if (InstantiationIsOkay) {
+ if (Var->getPointOfInstantiation().isInvalid())
+ Var->setTemplateSpecializationKind(TSK, Loc);
+
+ if (TryInstantiating) {
+ SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
bool InstantiationDependent = false;
bool IsNonDependent =
VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 09dd28e..065f75e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -7372,13 +7372,8 @@
CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
// Verify that it is okay to explicitly instantiate here.
- MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
- TemplateSpecializationKind PrevTSK =
- MSInfo ? MSInfo->getTemplateSpecializationKind()
- : Prev->getTemplateSpecializationKind();
- SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation()
- : cast<VarTemplateSpecializationDecl>(Prev)
- ->getPointOfInstantiation();
+ TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
+ SourceLocation POI = Prev->getPointOfInstantiation();
bool HasNoEffect = false;
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
PrevTSK, POI, HasNoEffect))
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index d85f7e4..32111ba 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2471,6 +2471,9 @@
}
}
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
+ if (isa<VarTemplateSpecializationDecl>(Var))
+ continue;
+
if (Var->isStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9779aa6..8f4c009 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -318,7 +318,6 @@
return Inst;
}
-// FIXME: Revise for static member templates.
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
}
@@ -2338,7 +2337,7 @@
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- SmallVectorImpl<TemplateArgument> &Converted) {
+ llvm::ArrayRef<TemplateArgument> Converted) {
// If this is the variable for an anonymous struct or union,
// instantiate the anonymous struct/union type first.
@@ -2366,7 +2365,8 @@
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
Converted.size());
Var->setTemplateArgsInfo(TemplateArgsInfo);
- VarTemplate->AddSpecialization(Var, InsertPos);
+ if (InsertPos)
+ VarTemplate->AddSpecialization(Var, InsertPos);
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
@@ -2691,12 +2691,8 @@
// specializations. The instantiation of the initializer is not necessary.
VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
- // Set the initializer, to use as pattern for initialization.
- if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
- PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
LateAttrs, Owner, StartingScope);
- InstPartialSpec->setInit(PartialSpec->getInit());
return InstPartialSpec;
}
@@ -3309,8 +3305,15 @@
MultiLevelTemplateArgumentList TemplateArgLists;
TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
+ // Instantiate the first declaration of the variable template: for a partial
+ // specialization of a static data member template, the first declaration may
+ // or may not be the declaration in the class; if it's in the class, we want
+ // to instantiate a member in the class (a declaration), and if it's outside,
+ // we want to instantiate a definition.
+ FromVar = FromVar->getFirstDeclaration();
+
TemplateDeclInstantiator Instantiator(
- *this, VarTemplate->getDeclContext(),
+ *this, FromVar->getDeclContext(),
MultiLevelTemplateArgumentList(TemplateArgList));
// TODO: Set LateAttrs and StartingScope ...
@@ -3327,10 +3330,8 @@
const MultiLevelTemplateArgumentList &TemplateArgs) {
// Do substitution on the type of the declaration
- MultiLevelTemplateArgumentList Innermost;
- Innermost.addOuterTemplateArguments(TemplateArgs.getInnermost());
TypeSourceInfo *DI =
- SubstType(PatternDecl->getTypeSourceInfo(), Innermost,
+ SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
if (!DI)
return 0;
@@ -3429,14 +3430,9 @@
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
- if (isa<VarTemplateSpecializationDecl>(NewVar)) {
- // Do not instantiate the variable just yet.
- } else if (InstantiatingVarTemplate) {
- assert(!NewVar->getInit() &&
- "A variable should not have an initializer if it is templated"
- " and we are instantiating its template");
- NewVar->setInit(OldVar->getInit());
- } else
+ // Delay instantiation of the initializer for variable templates until a
+ // definition of the variable is needed.
+ if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate)
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
// Diagnose unused local variables with dependent types, where the diagnostic
@@ -3513,19 +3509,18 @@
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
bool DefinitionRequired) {
-
if (Var->isInvalidDecl())
return;
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
- assert((VarSpec || Var->isStaticDataMember()) &&
- "Not a static data member, nor a variable template specialization?");
- VarDecl *PatternDecl = 0;
+ VarDecl *PatternDecl = 0, *Def = 0;
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Var);
- // If this is a variable template specialization, make sure that it is
- // non-dependent, then find its instantiation pattern.
if (VarSpec) {
+ // If this is a variable template specialization, make sure that it is
+ // non-dependent, then find its instantiation pattern.
bool InstantiationDependent = false;
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
@@ -3533,59 +3528,123 @@
"not type-dependent");
(void)InstantiationDependent;
- // Find the variable initialization that we'll be substituting.
+ // 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 *>()) {
- PatternDecl = cast<VarDecl>(
- PatternPtr.get<VarTemplatePartialSpecializationDecl *>());
+ VarTemplatePartialSpecializationDecl *Tmpl =
+ PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
+ while (VarTemplatePartialSpecializationDecl *From =
+ Tmpl->getInstantiatedFromMember()) {
+ if (Tmpl->isMemberSpecialization())
+ break;
- // Find actual definition
- if (VarDecl *Def = PatternDecl->getDefinition(getASTContext()))
- PatternDecl = Def;
+ Tmpl = From;
+ }
+ PatternDecl = Tmpl;
} else {
- VarTemplateDecl *PatternTemplate = PatternPtr.get<VarTemplateDecl *>();
+ VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
+ while (VarTemplateDecl *From =
+ Tmpl->getInstantiatedFromMemberTemplate()) {
+ if (Tmpl->isMemberSpecialization())
+ break;
- // Find actual definition
- if (VarTemplateDecl *Def = PatternTemplate->getDefinition())
- PatternTemplate = Def;
-
- PatternDecl = PatternTemplate->getTemplatedDecl();
+ Tmpl = From;
+ }
+ PatternDecl = Tmpl->getTemplatedDecl();
}
- assert(PatternDecl && "instantiating a non-template");
+
+ // If this is a static data member template, there might be an
+ // uninstantiated initializer on the declaration. If so, instantiate
+ // it now.
+ if (PatternDecl->isStaticDataMember() &&
+ (PatternDecl = PatternDecl->getFirstDeclaration())->hasInit() &&
+ !Var->hasInit()) {
+ // FIXME: Factor out the duplicated instantiation context setup/tear down
+ // code here.
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst)
+ return;
+
+ // If we're performing recursive template instantiation, create our own
+ // queue of pending implicit instantiations that we will instantiate
+ // later, while we're still within our own instantiation context.
+ SmallVector<VTableUse, 16> SavedVTableUses;
+ std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
+ if (Recursive) {
+ VTableUses.swap(SavedVTableUses);
+ PendingInstantiations.swap(SavedPendingInstantiations);
+ }
+
+ LocalInstantiationScope Local(*this);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ ContextRAII PreviousContext(*this, Var->getDeclContext());
+ InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
+ PreviousContext.pop();
+
+ // FIXME: Need to inform the ASTConsumer that we instantiated the
+ // initializer?
+
+ // This variable may have local implicit instantiations that need to be
+ // instantiated within this scope.
+ PerformPendingInstantiations(/*LocalOnly=*/true);
+
+ Local.Exit();
+
+ if (Recursive) {
+ // Define any newly required vtables.
+ DefineUsedVTables();
+
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingInstantiations();
+
+ // Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded.");
+ VTableUses.swap(SavedVTableUses);
+
+ // Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded.");
+ PendingInstantiations.swap(SavedPendingInstantiations);
+ }
+ }
+
+ // 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->getOutOfLineDefinition();
}
- // If this is a static data member, find its out-of-line definition.
- VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
- if (Var->isStaticDataMember()) {
- assert(Def && "This data member was not instantiated from a template?");
- assert(Def->isStaticDataMember() && "Not a static data member?");
- Def = Def->getOutOfLineDefinition();
- }
-
- // If the instantiation pattern does not have an initializer, or if an
- // out-of-line definition is not found, we won't perform any instantiation.
- // Rather, we rely on the user to instantiate this definition (or provide
- // a specialization for it) in another translation unit.
- if ((VarSpec && !PatternDecl->getInit()) ||
- (!VarSpec && Var->isStaticDataMember() && !Def)) {
+ // 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
+ // definition (or provide a specialization for it) in another translation
+ // unit.
+ if (!Def) {
if (DefinitionRequired) {
- if (!Var->isStaticDataMember()) {
+ if (VarSpec)
Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_var_template)
- << PatternDecl;
- Diag(PatternDecl->getLocation(),
- diag::note_explicit_instantiation_here);
- } else {
- Def = Var->getInstantiatedFromStaticDataMember();
+ diag::err_explicit_instantiation_undefined_var_template) << Var;
+ else
Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_member)
- << 3 << Var->getDeclName() << Var->getDeclContext();
- Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
- }
+ << 2 << Var->getDeclName() << Var->getDeclContext();
+ Diag(PatternDecl->getLocation(),
+ diag::note_explicit_instantiation_here);
if (VarSpec)
Var->setInvalidDecl();
} else if (Var->getTemplateSpecializationKind()
@@ -3603,11 +3662,6 @@
if (TSK == TSK_ExplicitSpecialization)
return;
- // C++0x [temp.explicit]p9:
- // Except for inline functions, other explicit instantiation declarations
- // have the effect of suppressing the implicit instantiation of the entity
- // to which they refer.
- //
// C++11 [temp.explicit]p10:
// Except for inline functions, [...] explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
@@ -3624,24 +3678,17 @@
: Consumer(Consumer), Var(Var) { }
~PassToConsumerRAII() {
- if (Var->isStaticDataMember())
- Consumer.HandleCXXStaticMemberVarInstantiation(Var);
- else {
- DeclGroupRef DG(Var);
- Consumer.HandleTopLevelDecl(DG);
- }
+ Consumer.HandleCXXStaticMemberVarInstantiation(Var);
}
} PassToConsumerRAII(Consumer, Var);
- if (!VarSpec) {
- // If we already have a definition, we're done.
- if (VarDecl *Def = Var->getDefinition()) {
- // We may be explicitly instantiating something we've already implicitly
- // instantiated.
- Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
- PointOfInstantiation);
- return;
- }
+ // If we already have a definition, we're done.
+ if (VarDecl *Def = Var->getDefinition()) {
+ // We may be explicitly instantiating something we've already implicitly
+ // instantiated.
+ Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
+ PointOfInstantiation);
+ return;
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
@@ -3666,29 +3713,46 @@
VarDecl *OldVar = Var;
if (!VarSpec)
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
- getTemplateInstantiationArgs(Var)));
- else
- // Construct a VarTemplateSpecializationDecl to avoid name clashing with
- // the primary template. (Note that unlike function declarations, variable
- // declarations cannot be overloaded.)
- // In fact, there is no need to construct a new declaration from scratch.
- // Thus, simply complete its definition with an appropriately substituted
- // type and initializer.
- Var = CompleteVarTemplateSpecializationDecl(
- VarSpec, PatternDecl, getTemplateInstantiationArgs(Var));
+ TemplateArgs));
+ else if (Var->isStaticDataMember() &&
+ Var->getLexicalDeclContext()->isRecord()) {
+ // We need to instantiate the definition of a static data member template,
+ // and all we have is the in-class declaration of it. Instantiate a separate
+ // declaration of the definition.
+ TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
+ TemplateArgs);
+ Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
+ VarSpec->getSpecializedTemplate(), Def, 0,
+ VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray()));
+ if (Var) {
+ llvm::PointerUnion<VarTemplateDecl *,
+ VarTemplatePartialSpecializationDecl *> PatternPtr =
+ VarSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+ cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf(
+ Partial, &VarSpec->getTemplateInstantiationArgs());
+
+ // Merge the definition with the declaration.
+ LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
+ LookupOrdinaryName, ForRedeclaration);
+ R.addDecl(OldVar);
+ MergeVarDecl(Var, R);
+
+ // Attach the initializer.
+ InstantiateVariableInitializer(Var, Def, TemplateArgs);
+ }
+ } else
+ // Complete the existing variable's definition with an appropriately
+ // substituted type and initializer.
+ Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs);
PreviousContext.pop();
if (Var) {
- MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
- if (!VarSpec)
- assert(MSInfo && "Missing member specialization information?");
-
PassToConsumerRAII.Var = Var;
- if (MSInfo)
- Var->setTemplateSpecializationKind(
- MSInfo->getTemplateSpecializationKind(),
- MSInfo->getPointOfInstantiation());
+ Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(),
+ OldVar->getPointOfInstantiation());
}
// This variable may have local implicit instantiations that need to be