aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-10-07 22:35:40 +0000
committerDouglas Gregor <dgregor@apple.com>2009-10-07 22:35:40 +0000
commit1fef4e60e7e884803977a8376c172ea584f8a5d1 (patch)
treeb93c74b60dbe4237f13dca5fa45b07e890fb39ad
parent6e8f550439c09f3f044d651354e297518b553712 (diff)
Type checking for specializations of member functions of class
templates. Previously, these weren't handled as specializations at all. The AST for representing these as specializations is still a work in progress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83498 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td8
-rw-r--r--lib/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaDecl.cpp38
-rw-r--r--lib/Sema/SemaTemplate.cpp97
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp14
-rw-r--r--test/SemaTemplate/class-template-spec.cpp5
6 files changed, 137 insertions, 30 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6c8b631e39..a93955be77 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -922,8 +922,8 @@ def err_template_spec_unknown_kind : Error<
"instantiation|instantiation}0 for a class template, function template, or "
"a member function, static data member, or member class of a class template">;
def note_specialized_entity : Note<
- "explicit %select{<error>|<error>|specialized|instantiated|instantiated}0 is "
- "here">;
+ "explicitly %select{<error>|<error>|specialized|instantiated|instantiated}0 "
+ "declaration is here">;
def err_template_spec_decl_function_scope : Error<
"explicit %select{<error>|<error>|specialization|instantiation|"
"instantiation}0 of %1 in function scope">;
@@ -946,6 +946,10 @@ 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 note_specialized_decl : Note<"attempt to specialize declaration here">;
// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2056d39132..6142eacd57 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2433,7 +2433,8 @@ public:
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
- unsigned NumParamLists);
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -2518,6 +2519,8 @@ public:
unsigned NumExplicitTemplateArgs,
SourceLocation RAngleLoc,
NamedDecl *&PrevDecl);
+ bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
+ NamedDecl *&PrevDecl);
virtual DeclResult
ActOnExplicitInstantiation(Scope *S,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a1fcf89c54..4743720c62 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2235,12 +2235,15 @@ 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(
+ = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
- D.getCXXScopeSpec(),
+ D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
- TemplateParamLists.size())) {
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// There is no such thing as a variable template.
Diag(D.getIdentifierLoc(), diag::err_template_variable)
@@ -2256,6 +2259,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
+
+ isExplicitSpecialization = true;
}
}
@@ -2660,13 +2665,15 @@ Sema::ActOnFunctionDeclarator(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.
FunctionTemplateDecl *FunctionTemplate = 0;
+ bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
- TemplateParamLists.size())) {
+ TemplateParamLists.size(),
+ isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -2847,7 +2854,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
RAngleLoc = TemplateId->RAngleLoc;
if (FunctionTemplate) {
- // FIXME: Diagnostic function template with explicit template
+ // FIXME: Diagnose function template with explicit template
// arguments.
HasExplicitTemplateArgs = false;
} else if (!isFunctionTemplateSpecialization &&
@@ -2865,13 +2872,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
- if (isFunctionTemplateSpecialization &&
- CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
- LAngleLoc, TemplateArgs.data(),
- TemplateArgs.size(), RAngleLoc,
- PrevDecl))
+ if (isFunctionTemplateSpecialization) {
+ if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs,
+ LAngleLoc, TemplateArgs.data(),
+ TemplateArgs.size(), RAngleLoc,
+ PrevDecl))
+ NewFD->setInvalidDecl();
+ } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
+ CheckMemberFunctionSpecialization(cast<CXXMethodDecl>(NewFD),
+ PrevDecl))
NewFD->setInvalidDecl();
-
+
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
@@ -4161,11 +4172,14 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
OwnedDecl = false;
TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ // FIXME: Check explicit specializations more carefully.
+ bool isExplicitSpecialization = false;
if (TUK != TUK_Reference) {
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
- TemplateParameterLists.size())) {
+ TemplateParameterLists.size(),
+ isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
// be a member of another template).
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 6792b28d1c..f3cd2e41fb 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -933,6 +933,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
///
/// \param NumParamLists the number of template parameter lists in ParamLists.
///
+/// \param IsExplicitSpecialization will be set true if the entity being
+/// declared is an explicit specialization, false otherwise.
+///
/// \returns the template parameter list, if any, that corresponds to the
/// name that is preceded by the scope specifier @p SS. This template
/// parameter list may be have template parameters (if we're declaring a
@@ -943,7 +946,10 @@ TemplateParameterList *
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
- unsigned NumParamLists) {
+ unsigned NumParamLists,
+ bool &IsExplicitSpecialization) {
+ IsExplicitSpecialization = false;
+
// Find the template-ids that occur within the nested-name-specifier. These
// template-ids will match up with the template parameter lists.
llvm::SmallVector<const TemplateSpecializationType *, 4>
@@ -1000,6 +1006,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
<< SS.getRange()
<< CodeModificationHint::CreateInsertion(FirstTemplateLoc,
"template<> ");
+ IsExplicitSpecialization = true;
}
return 0;
}
@@ -1031,6 +1038,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
diag::err_template_param_list_matches_nontemplate)
<< TemplateId
<< ParamLists[Idx]->getSourceRange();
+ else
+ IsExplicitSpecialization = true;
}
// If there were at least as many template-ids as there were template
@@ -2399,11 +2408,14 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// Keep these "kind" numbers in sync with the %select statements in the
// various diagnostics emitted by this routine.
int EntityKind = 0;
- if (isa<ClassTemplateDecl>(Specialized))
+ bool isTemplateSpecialization = false;
+ if (isa<ClassTemplateDecl>(Specialized)) {
EntityKind = IsPartialSpecialization? 1 : 0;
- else if (isa<FunctionTemplateDecl>(Specialized))
+ isTemplateSpecialization = true;
+ } else if (isa<FunctionTemplateDecl>(Specialized)) {
EntityKind = 2;
- else if (isa<CXXMethodDecl>(Specialized))
+ isTemplateSpecialization = true;
+ } else if (isa<CXXMethodDecl>(Specialized))
EntityKind = 3;
else if (isa<VarDecl>(Specialized))
EntityKind = 4;
@@ -2464,7 +2476,8 @@ static bool CheckTemplateSpecializationScope(Sema &S,
<< EntityKind << Specialized
<< cast<NamedDecl>(SpecializedContext);
- S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity)
+ << TSK;
ComplainedAboutScope = true;
}
}
@@ -2492,7 +2505,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
<< EntityKind << Specialized
<< cast<NamedDecl>(SpecializedContext);
- S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
}
// FIXME: check for specialization-after-instantiation errors and such.
@@ -2640,6 +2653,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+ bool isExplicitSpecialization = false;
bool isPartialSpecialization = false;
// Check the validity of the template headers that introduce this
@@ -2649,7 +2663,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
- TemplateParameterLists.size());
+ TemplateParameterLists.size(),
+ isExplicitSpecialization);
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
@@ -2684,9 +2699,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
}
}
- } else if (!TemplateParams && TUK != TUK_Friend)
+ } else if (!TemplateParams && TUK != TUK_Friend) {
Diag(KWLoc, diag::err_template_spec_needs_header)
<< CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ isExplicitSpecialization = true;
+ }
// Check that the specialization uses the same tag kind as the
// original template.
@@ -3101,6 +3118,70 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
return false;
}
+/// \brief Perform semantic analysis for the given member function
+/// specialization.
+///
+/// This routine performs all of the semantic analysis required for an
+/// explicit member function specialization. On successful completion,
+/// 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 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;
+ }
+ }
+ }
+
+ if (!Instantiation) {
+ // There is no previous declaration that matches. Since member function
+ // specializations are always out-of-line, the caller will complain about
+ // this mismatch later.
+ return false;
+ }
+
+ // 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;
+ Diag(Instantiation->getLocation(), diag::note_specialized_decl);
+ return true;
+ }
+
+ // Check the scope of this explicit specialization.
+ if (CheckTemplateSpecializationScope(*this,
+ FunctionInTemplate,
+ Instantiation, FD->getLocation(),
+ false, TSK_ExplicitSpecialization))
+ return true;
+
+ // FIXME: Mark the new declaration as a member function specialization.
+ // We may also want to mark the original instantiation as having been
+ // explicitly specialized.
+
+ // Save the caller the trouble of having to figure out which declaration
+ // this specialization matches.
+ PrevDecl = Instantiation;
+ return false;
+}
+
// Explicit instantiation of a class template specialization
// FIXME: Implement extern template semantics
Sema::DeclResult
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 77df60a25d..553d62c9e5 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -51,7 +51,7 @@ template<typename T>
struct X0 { // expected-note 2{{here}}
static T member;
- void f1(T t) {
+ void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
t = 17;
}
@@ -85,17 +85,21 @@ namespace N0 {
template<> struct X0<volatile void>;
}
-template<> struct N0::X0<volatile void> { };
+template<> struct N0::X0<volatile void> {
+ void f1(void *);
+};
// -- member function of a class template
-// FIXME: this should complain about the scope of f1, but we don't seem
-// to recognize it as a specialization. Hrm?
-template<> void N0::X0<void*>::f1(void *) { }
+template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
void test_spec(N0::X0<void*> xvp, void *vp) {
xvp.f1(vp);
}
+namespace N0 {
+ template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
+}
+
#if 0
// FIXME: update the remainder of this test to check for scopes properly.
// -- static data member of a class template
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
index e4d917f775..05ddb05325 100644
--- a/test/SemaTemplate/class-template-spec.cpp
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -1,5 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
-template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}}
+template<typename T, typename U = int> struct A; // expected-note {{template is declared here}} \
+ // expected-note{{explicitly specialized}}
template<> struct A<double, double>; // expected-note{{forward declaration}}
@@ -74,7 +75,7 @@ struct A<double> { }; // expected-error{{template specialization requires 'templ
template<> struct ::A<double>;
namespace N {
- template<typename T> struct B; // expected-note 2{{template is declared here}}
+ template<typename T> struct B; // expected-note 2{{explicitly specialized}}
template<> struct ::N::B<char>; // okay
template<> struct ::N::B<short>; // okay