aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
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 /lib/Sema
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
Diffstat (limited to 'lib/Sema')
-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
6 files changed, 108 insertions, 49 deletions
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)