aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-10-08 07:24:58 +0000
committerDouglas Gregor <dgregor@apple.com>2009-10-08 07:24:58 +0000
commit251b4ff2578e26959a4c036140ccd61c5e9292f2 (patch)
treecacc1f2c9bfb3174e9914422eef9de64890b06cd
parente9374d5e2c0915bd883dfa988db2451b844390d8 (diff)
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
-rw-r--r--include/clang/AST/ASTContext.h13
-rw-r--r--include/clang/AST/Decl.h54
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/AST/ASTContext.cpp11
-rw-r--r--lib/AST/Decl.cpp21
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaDecl.cpp20
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaTemplate.cpp91
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp9
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp28
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp23
12 files changed, 193 insertions, 91 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index bb9e3861be..63f909146e 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -154,7 +154,8 @@ class ASTContext {
///
/// This data structure stores the mapping from instantiations of static
/// data members to the static data member representations within the
- /// class template from which they were instantiated.
+ /// class template from which they were instantiated along with the kind
+ /// of instantiation or specialization (a TemplateSpecializationKind - 1).
///
/// Given the following example:
///
@@ -172,8 +173,9 @@ class ASTContext {
///
/// This mapping will contain an entry that maps from the VarDecl for
/// X<int>::value to the corresponding VarDecl for X<T>::value (within the
- /// class template X).
- llvm::DenseMap<VarDecl *, VarDecl *> InstantiatedFromStaticDataMember;
+ /// class template X) and will be marked TSK_ImplicitInstantiation.
+ llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>
+ InstantiatedFromStaticDataMember;
/// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls
/// where created during instantiation.
@@ -265,11 +267,12 @@ public:
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
- VarDecl *getInstantiatedFromStaticDataMember(VarDecl *Var);
+ MemberSpecializationInfo *getInstantiatedFromStaticDataMember(VarDecl *Var);
/// \brief Note that the static data member \p Inst is an instantiation of
/// the static data member template \p Tmpl of a class template.
- void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl);
+ void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
+ TemplateSpecializationKind TSK);
/// \brief If this using decl is instantiated from an unresolved using decl,
/// return it.
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index f2ffccd7e0..0e91511dbd 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -300,6 +300,29 @@ struct EvaluatedStmt {
APValue Evaluated;
};
+// \brief Describes the kind of template specialization that a
+// particular template specialization declaration represents.
+enum TemplateSpecializationKind {
+ /// This template specialization was formed from a template-id but
+ /// has not yet been declared, defined, or instantiated.
+ TSK_Undeclared = 0,
+ /// This template specialization was implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// This template specialization was declared or defined by an
+ /// explicit specialization (C++ [temp.expl.spec]) or partial
+ /// specialization (C++ [temp.class.spec]).
+ TSK_ExplicitSpecialization,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation declaration request
+ /// (C++0x [temp.explicit]).
+ TSK_ExplicitInstantiationDeclaration,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation definition request
+ /// (C++ [temp.explicit]).
+ TSK_ExplicitInstantiationDefinition
+};
+
/// VarDecl - An instance of this class is created to represent a variable
/// declaration or definition.
class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
@@ -566,6 +589,14 @@ public:
/// from which it was instantiated.
VarDecl *getInstantiatedFromStaticDataMember();
+ /// \brief If this variable is a static data member, determine what kind of
+ /// template specialization or instantiation this is.
+ TemplateSpecializationKind getTemplateSpecializationKind();
+
+ /// \brief For a static data member that was instantiated from a static
+ /// data member of a class template, set the template specialiation kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
/// isFileVarDecl - Returns true for file scoped variable declaration.
bool isFileVarDecl() const {
if (getKind() != Decl::Var)
@@ -754,29 +785,6 @@ public:
static bool classof(const OriginalParmVarDecl *D) { return true; }
};
-// \brief Describes the kind of template specialization that a
-// particular template specialization declaration represents.
-enum TemplateSpecializationKind {
- /// This template specialization was formed from a template-id but
- /// has not yet been declared, defined, or instantiated.
- TSK_Undeclared = 0,
- /// This template specialization was implicitly instantiated from a
- /// template. (C++ [temp.inst]).
- TSK_ImplicitInstantiation,
- /// This template specialization was declared or defined by an
- /// explicit specialization (C++ [temp.expl.spec]) or partial
- /// specialization (C++ [temp.class.spec]).
- TSK_ExplicitSpecialization,
- /// This template specialization was instantiated from a template
- /// due to an explicit instantiation declaration request
- /// (C++0x [temp.explicit]).
- TSK_ExplicitInstantiationDeclaration,
- /// This template specialization was instantiated from a template
- /// due to an explicit instantiation definition request
- /// (C++ [temp.explicit]).
- TSK_ExplicitInstantiationDefinition
-};
-
/// FunctionDecl - An instance of this class is created to represent a
/// function declaration or definition.
///
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 3273f2b783..09f39513b4 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -948,9 +948,8 @@ def err_template_spec_redecl_global_scope : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must occur "
"at global scope">;
-def err_function_spec_not_instantiated : Error<
- "specialization of member function %q0 does not specialize an instantiated "
- "member function">;
+def err_spec_member_not_instantiated : Error<
+ "specialization of member %q0 does not specialize an instantiated member">;
def note_specialized_decl : Note<"attempt to specialize declaration here">;
// C++ class template specializations and out-of-line definitions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 1fa492c874..85b4fd6d6c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -232,9 +232,10 @@ void ASTContext::InitBuiltinTypes() {
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 @@ VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
}
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 a5c9fa4bac..5584e4c3da 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -371,7 +371,26 @@ SourceRange VarDecl::getSourceRange() const {
}
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 6142eacd57..08cb06db56 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2519,8 +2519,7 @@ public:
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 d612bb8351..2070335a61 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2193,7 +2193,6 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 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 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
!(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 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
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 3bd72d07d2..c9525f39e5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6209,11 +6209,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
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 9d3efa60b0..5c6ec0004a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2365,8 +2365,9 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
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 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
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 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
/// 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 @@ Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
// 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 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// 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 ee6600adc6..2f7af60e05 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -982,9 +982,12 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
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 fcacb4a3f0..bafcea054e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -155,6 +155,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
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 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
} 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 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
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 @@ void Sema::InstantiateStaticDataMemberDefinition(
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 @@ void Sema::InstantiateStaticDataMemberDefinition(
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)
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
index 413d0b949d..438c41159a 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -49,7 +49,7 @@ namespace N0 {
template<typename T>
struct X0 { // expected-note 2{{here}}
- static T member;
+ static T member; // expected-note{{here}}
void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
t = 17;
@@ -106,16 +106,27 @@ void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) {
x0.f1(cvp); // okay: we've explicitly specialized
}
-#if 0
-// FIXME: update the remainder of this test to check for scopes properly.
// -- static data member of a class template
-template<>
-NonDefaultConstructible X0<NonDefaultConstructible>::member = 17;
+namespace N0 {
+ // This actually tests p15; the following is a declaration, not a definition.
+ template<>
+ NonDefaultConstructible X0<NonDefaultConstructible>::member;
+
+ template<> long X0<long>::member = 17;
+
+ template<> float X0<float>::member;
+}
NonDefaultConstructible &get_static_member() {
- return X0<NonDefaultConstructible>::member;
+ return N0::X0<NonDefaultConstructible>::member;
}
+template<> int N0::X0<int>::member; // expected-error{{originally}}
+
+template<> float N0::X0<float>::member = 3.14f;
+
+#if 0
+// FIXME: update the remainder of this test to check for scopes properly.
// -- member class of a class template
template<>
struct X0<void*>::Inner { };