[cfe-commits] r83498 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp test/SemaTemplate/class-template-spec.cpp
Douglas Gregor
dgregor at apple.com
Wed Oct 7 15:35:40 PDT 2009
Author: dgregor
Date: Wed Oct 7 17:35:40 2009
New Revision: 83498
URL: http://llvm.org/viewvc/llvm-project?rev=83498&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
cfe/trunk/test/SemaTemplate/class-template-spec.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct 7 17:35:40 2009
@@ -922,8 +922,8 @@
"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 @@
"%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<
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 7 17:35:40 2009
@@ -2433,7 +2433,8 @@
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 @@
unsigned NumExplicitTemplateArgs,
SourceLocation RAngleLoc,
NamedDecl *&PrevDecl);
+ bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD,
+ NamedDecl *&PrevDecl);
virtual DeclResult
ActOnExplicitInstantiation(Scope *S,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Oct 7 17:35:40 2009
@@ -2235,12 +2235,15 @@
// 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 @@
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
+
+ isExplicitSpecialization = true;
}
}
@@ -2660,13 +2665,15 @@
// 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 @@
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 @@
}
}
- 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 @@
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).
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct 7 17:35:40 2009
@@ -933,6 +933,9 @@
///
/// \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 @@
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 @@
<< SS.getRange()
<< CodeModificationHint::CreateInsertion(FirstTemplateLoc,
"template<> ");
+ IsExplicitSpecialization = true;
}
return 0;
}
@@ -1031,6 +1038,8 @@
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 @@
// 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 @@
<< 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 @@
<< 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 @@
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 @@
TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
- TemplateParameterLists.size());
+ TemplateParameterLists.size(),
+ isExplicitSpecialization);
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
@@ -2684,9 +2699,11 @@
}
}
}
- } 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 @@
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
Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp Wed Oct 7 17:35:40 2009
@@ -51,7 +51,7 @@
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 @@
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
Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=83498&r1=83497&r2=83498&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Wed Oct 7 17:35:40 2009
@@ -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 @@
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
More information about the cfe-commits
mailing list