For instantiations of static data members of class templates, keep
track of the kind of specialization or instantiation. Also, check the
scope of the specialization and ensure that a specialization
declaration without an initializer is not a definition.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83533 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 1fa492c..85b4fd6 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -232,9 +232,10 @@
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
}
-VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
+MemberSpecializationInfo *
+ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
- llvm::DenseMap<VarDecl *, VarDecl *>::iterator Pos
+ llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>::iterator Pos
= InstantiatedFromStaticDataMember.find(Var);
if (Pos == InstantiatedFromStaticDataMember.end())
return 0;
@@ -243,12 +244,14 @@
}
void
-ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl) {
+ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+ TemplateSpecializationKind TSK) {
assert(Inst->isStaticDataMember() && "Not a static data member");
assert(Tmpl->isStaticDataMember() && "Not a static data member");
assert(!InstantiatedFromStaticDataMember[Inst] &&
"Already noted what static data member was instantiated from");
- InstantiatedFromStaticDataMember[Inst] = Tmpl;
+ InstantiatedFromStaticDataMember[Inst]
+ = new (*this) MemberSpecializationInfo(Tmpl, TSK);
}
UnresolvedUsingDecl *
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a5c9fa4..5584e4c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -371,7 +371,26 @@
}
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() {
- return getASTContext().getInstantiatedFromStaticDataMember(this);
+ if (MemberSpecializationInfo *MSI
+ = getASTContext().getInstantiatedFromStaticDataMember(this))
+ return cast<VarDecl>(MSI->getInstantiatedFrom());
+
+ return 0;
+}
+
+TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() {
+ if (MemberSpecializationInfo *MSI
+ = getASTContext().getInstantiatedFromStaticDataMember(this))
+ return MSI->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ MemberSpecializationInfo *MSI
+ = getASTContext().getInstantiatedFromStaticDataMember(this);
+ assert(MSI && "Not an instantiated static data member?");
+ MSI->setTemplateSpecializationKind(TSK);
}
bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6142eac..08cb06d 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2519,8 +2519,7 @@
unsigned NumExplicitTemplateArgs,
SourceLocation RAngleLoc,
NamedDecl *&PrevDecl);
- bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
- NamedDecl *&PrevDecl);
+ bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl);
virtual DeclResult
ActOnExplicitInstantiation(Scope *S,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d612bb8..2070335 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2193,7 +2193,6 @@
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- // FIXME: Actually record when this is an explicit specialization!
bool isExplicitSpecialization = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
@@ -2259,7 +2258,7 @@
!(NewVD->hasLinkage() &&
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
PrevDecl = 0;
-
+
// Merge the decl with the existing one if appropriate.
if (PrevDecl) {
if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
@@ -2281,6 +2280,11 @@
CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration);
+ // This is an explicit specialization of a static data member. Check it.
+ if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ CheckMemberSpecialization(NewVD, PrevDecl))
+ NewVD->setInvalidDecl();
+
// attributes declared post-definition are currently ignored
if (PrevDecl) {
const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl);
@@ -2837,8 +2841,7 @@
PrevDecl))
NewFD->setInvalidDecl();
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
- CheckMemberFunctionSpecialization(cast<CXXMethodDecl>(NewFD),
- PrevDecl))
+ CheckMemberSpecialization(NewFD, PrevDecl))
NewFD->setInvalidDecl();
// Perform semantic checking on the function declaration.
@@ -3400,6 +3403,15 @@
return;
}
+ // C++ [temp.expl.spec]p15:
+ // An explicit specialization of a static data member of a template is a
+ // definition if the declaration includes an initializer; otherwise, it
+ // is a declaration.
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember() &&
+ Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
// C++ [dcl.init]p9:
// If no initializer is specified for an object, and the object
// is of (possibly cv-qualified) non-POD class type (or array
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3bd72d0..c9525f3 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6209,11 +6209,9 @@
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Implicit instantiation of static data members of class templates.
- // FIXME: distinguish between implicit instantiations (which we need to
- // actually instantiate) and explicit specializations.
- // FIXME: extern templates
if (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember())
+ Var->getInstantiatedFromStaticDataMember() &&
+ Var->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
// FIXME: keep track of references to static data?
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 9d3efa6..5c6ec00 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2365,8 +2365,9 @@
return CTS->getSpecializationKind();
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
return Function->getTemplateSpecializationKind();
-
- // FIXME: static data members!
+ if (VarDecl *Var = dyn_cast<VarDecl>(D))
+ return Var->getTemplateSpecializationKind();
+
// FIXME: member classes of class templates!
return TSK_Undeclared;
}
@@ -3118,7 +3119,7 @@
return false;
}
-/// \brief Perform semantic analysis for the given member function
+/// \brief Perform semantic analysis for the given non-template member
/// specialization.
///
/// This routine performs all of the semantic analysis required for an
@@ -3126,27 +3127,45 @@
/// the function declaration \p FD will become a member function
/// specialization.
///
-/// \param FD the function declaration, which will be updated to become a
-/// function template specialization.
+/// \param Member the member declaration, which will be updated to become a
+/// specialization.
///
/// \param PrevDecl the set of declarations, one of which may be specialized
/// by this function specialization.
bool
-Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
- NamedDecl *&PrevDecl) {
- // Try to find the member function we are instantiating.
- CXXMethodDecl *Instantiation = 0;
- for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
- if (Context.hasSameType(FD->getType(), Method->getType())) {
- Instantiation = Method;
- break;
+Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
+ assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
+
+ // Try to find the member we are instantiating.
+ NamedDecl *Instantiation = 0;
+ NamedDecl *InstantiatedFrom = 0;
+ if (!PrevDecl) {
+ // Nowhere to look anyway.
+ } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) {
+ for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) {
+ if (Context.hasSameType(Function->getType(), Method->getType())) {
+ Instantiation = Method;
+ InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
+ break;
+ }
}
}
+ } else if (isa<VarDecl>(Member)) {
+ if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl))
+ if (PrevVar->isStaticDataMember()) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
+ }
+ } else if (isa<RecordDecl>(Member)) {
+ if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) {
+ Instantiation = PrevDecl;
+ InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
+ }
}
if (!Instantiation) {
- // There is no previous declaration that matches. Since member function
+ // There is no previous declaration that matches. Since member
// specializations are always out-of-line, the caller will complain about
// this mismatch later.
return false;
@@ -3155,30 +3174,43 @@
// FIXME: Check if the prior declaration has a point of instantiation.
// If so, we have run afoul of C++ [temp.expl.spec]p6.
- // Make sure that this is a specialization of a member function.
- FunctionDecl *FunctionInTemplate
- = Instantiation->getInstantiatedFromMemberFunction();
- if (!FunctionInTemplate) {
- Diag(FD->getLocation(), diag::err_function_spec_not_instantiated)
- << FD;
+ // Make sure that this is a specialization of a member.
+ if (!InstantiatedFrom) {
+ Diag(Member->getLocation(), diag::err_spec_member_not_instantiated)
+ << Member;
Diag(Instantiation->getLocation(), diag::note_specialized_decl);
return true;
}
// Check the scope of this explicit specialization.
if (CheckTemplateSpecializationScope(*this,
- FunctionInTemplate,
- Instantiation, FD->getLocation(),
+ InstantiatedFrom,
+ Instantiation, Member->getLocation(),
false, TSK_ExplicitSpecialization))
return true;
// FIXME: Check for specialization-after-instantiation errors and such.
- // Note that this function is an explicit instantiation of a member function.
- Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
- FD->setInstantiationOfMemberFunction(FunctionInTemplate,
- TSK_ExplicitSpecialization);
-
+ // Note that this is an explicit instantiation of a member.
+ if (isa<FunctionDecl>(Member)) {
+ // FIXME: We're also setting the original instantiation we found to be
+ // an explicit specialization, although I'd rather not have to do this.
+ cast<FunctionDecl>(Instantiation)->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else if (isa<VarDecl>(Member)) {
+ Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
+ cast<VarDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
+ } else {
+ assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+ // FIXME: Record TSK_ExplicitSpecialization.
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom));
+ }
+
// Save the caller the trouble of having to figure out which declaration
// this specialization matches.
PrevDecl = Instantiation;
@@ -3547,7 +3579,8 @@
}
// Instantiate static data member.
- // FIXME: Note that this is an explicit instantiation.
+ // FIXME: Check for prior specializations and such.
+ Prev->setTemplateSpecializationKind(TSK);
if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index ee6600a..2f7af60 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -982,9 +982,12 @@
if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
- if (Var->isStaticDataMember() &&
- TSK != TSK_ExplicitInstantiationDeclaration)
- InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ if (Var->isStaticDataMember()) {
+ Var->setTemplateSpecializationKind(TSK);
+
+ if (TSK != TSK_ExplicitInstantiationDeclaration)
+ InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ }
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
if (Record->isInjectedClassName())
continue;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fcacb4a..bafcea0 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -155,6 +155,12 @@
Owner->addDecl(Var);
}
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Var->isStaticDataMember())
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
+ TSK_ImplicitInstantiation);
+
if (D->getInit()) {
OwningExprResult Init
= SemaRef.SubstExpr(D->getInit(), TemplateArgs);
@@ -191,11 +197,6 @@
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Var->isStaticDataMember())
- SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D);
-
return Var;
}
@@ -977,6 +978,10 @@
assert(!Function->getBody() && "Already instantiated!");
+ // Never instantiate an explicit specialization.
+ if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
@@ -1084,7 +1089,6 @@
return;
// Find the out-of-line definition of this static data member.
- // FIXME: Do we have to look for specializations separately?
VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
bool FoundOutOfLineDef = false;
assert(Def && "This data member was not instantiated from a template?");
@@ -1106,7 +1110,17 @@
return;
}
- // FIXME: extern templates
+ // Never instantiate an explicit specialization.
+ if (Def->getTemplateSpecializationKind() == 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.
+ if (Def->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ return;
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)