зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
6e8f550439
Коммит
1fef4e60e7
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче