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
This commit is contained in:
Douglas Gregor 2009-10-07 22:35:40 +00:00
Родитель 6e8f550439
Коммит 1fef4e60e7
6 изменённых файлов: 137 добавлений и 30 удалений

Просмотреть файл

@ -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<

Просмотреть файл

@ -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,

Просмотреть файл

@ -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).

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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