forked from OSchip/llvm-project
Diagnose ill-formed uses of default template arguments in
function templates (in C++98), friend function templates, and out-of-line definitions of members of class templates. Also handles merging of default template arguments from previous declarations of function templates, for C++0x. However, we don't yet make use of those default template arguments. llvm-svn: 89872
This commit is contained in:
parent
58bf6e1885
commit
ed5731f68a
|
|
@ -919,6 +919,14 @@ def note_template_param_prev_default_arg : Note<
|
||||||
"previous default template argument defined here">;
|
"previous default template argument defined here">;
|
||||||
def err_template_param_default_arg_missing : Error<
|
def err_template_param_default_arg_missing : Error<
|
||||||
"template parameter missing a default argument">;
|
"template parameter missing a default argument">;
|
||||||
|
def err_template_parameter_default_in_function_template : Error<
|
||||||
|
"a template parameter of a function template cannot have a default argument "
|
||||||
|
"in C++98">;
|
||||||
|
def err_template_parameter_default_template_member : Error<
|
||||||
|
"cannot add a default template argument to the definition of a member of a "
|
||||||
|
"class template">;
|
||||||
|
def err_template_parameter_default_friend_template : Error<
|
||||||
|
"default template argument not permitted on a friend template">;
|
||||||
|
|
||||||
def err_template_variable : Error<"variable %0 declared as a template">;
|
def err_template_variable : Error<"variable %0 declared as a template">;
|
||||||
def err_template_variable_noparams : Error<
|
def err_template_variable_noparams : Error<
|
||||||
|
|
|
||||||
|
|
@ -2256,8 +2256,19 @@ public:
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
DeclPtrTy *Params, unsigned NumParams,
|
DeclPtrTy *Params, unsigned NumParams,
|
||||||
SourceLocation RAngleLoc);
|
SourceLocation RAngleLoc);
|
||||||
|
|
||||||
|
/// \brief The context in which we are checking a template parameter
|
||||||
|
/// list.
|
||||||
|
enum TemplateParamListContext {
|
||||||
|
TPC_ClassTemplate,
|
||||||
|
TPC_FunctionTemplate,
|
||||||
|
TPC_ClassTemplateMember,
|
||||||
|
TPC_FriendFunctionTemplate
|
||||||
|
};
|
||||||
|
|
||||||
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
|
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
TemplateParameterList *OldParams);
|
TemplateParameterList *OldParams,
|
||||||
|
TemplateParamListContext TPC);
|
||||||
TemplateParameterList *
|
TemplateParameterList *
|
||||||
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||||
const CXXScopeSpec &SS,
|
const CXXScopeSpec &SS,
|
||||||
|
|
|
||||||
|
|
@ -3025,6 +3025,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
|
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
|
||||||
"previous declaration set still overloaded");
|
"previous declaration set still overloaded");
|
||||||
|
|
||||||
|
// If we have a function template, check the template parameter
|
||||||
|
// list. This will check and merge default template arguments.
|
||||||
|
if (FunctionTemplate) {
|
||||||
|
FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration();
|
||||||
|
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
|
||||||
|
PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
|
||||||
|
D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate
|
||||||
|
: TPC_FunctionTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
|
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
|
||||||
// An out-of-line member function declaration must also be a
|
// An out-of-line member function declaration must also be a
|
||||||
// definition (C++ [dcl.meaning]p1).
|
// definition (C++ [dcl.meaning]p1).
|
||||||
|
|
|
||||||
|
|
@ -354,9 +354,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
|
||||||
|
|
||||||
if (CheckEquivalentExceptionSpec(
|
if (CheckEquivalentExceptionSpec(
|
||||||
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
|
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
|
||||||
New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
|
New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
}
|
|
||||||
|
|
||||||
return Invalid;
|
return Invalid;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -925,7 +925,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||||
// merging in the template parameter list from the previous class
|
// merging in the template parameter list from the previous class
|
||||||
// template declaration.
|
// template declaration.
|
||||||
if (CheckTemplateParameterList(TemplateParams,
|
if (CheckTemplateParameterList(TemplateParams,
|
||||||
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
|
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
|
||||||
|
TPC_ClassTemplate))
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
|
||||||
// FIXME: If we had a scope specifier, we better have a previous template
|
// FIXME: If we had a scope specifier, we better have a previous template
|
||||||
|
|
@ -1006,6 +1007,55 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||||
return DeclPtrTy::make(NewTemplate);
|
return DeclPtrTy::make(NewTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Diagnose the presence of a default template argument on a
|
||||||
|
/// template parameter, which is ill-formed in certain contexts.
|
||||||
|
///
|
||||||
|
/// \returns true if the default template argument should be dropped.
|
||||||
|
static bool DiagnoseDefaultTemplateArgument(Sema &S,
|
||||||
|
Sema::TemplateParamListContext TPC,
|
||||||
|
SourceLocation ParamLoc,
|
||||||
|
SourceRange DefArgRange) {
|
||||||
|
switch (TPC) {
|
||||||
|
case Sema::TPC_ClassTemplate:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Sema::TPC_FunctionTemplate:
|
||||||
|
// C++ [temp.param]p9:
|
||||||
|
// A default template-argument shall not be specified in a
|
||||||
|
// function template declaration or a function template
|
||||||
|
// definition [...]
|
||||||
|
// (This sentence is not in C++0x, per DR226).
|
||||||
|
if (!S.getLangOptions().CPlusPlus0x)
|
||||||
|
S.Diag(ParamLoc,
|
||||||
|
diag::err_template_parameter_default_in_function_template)
|
||||||
|
<< DefArgRange;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Sema::TPC_ClassTemplateMember:
|
||||||
|
// C++0x [temp.param]p9:
|
||||||
|
// A default template-argument shall not be specified in the
|
||||||
|
// template-parameter-lists of the definition of a member of a
|
||||||
|
// class template that appears outside of the member's class.
|
||||||
|
S.Diag(ParamLoc, diag::err_template_parameter_default_template_member)
|
||||||
|
<< DefArgRange;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Sema::TPC_FriendFunctionTemplate:
|
||||||
|
// C++ [temp.param]p9:
|
||||||
|
// A default template-argument shall not be specified in a
|
||||||
|
// friend template declaration.
|
||||||
|
S.Diag(ParamLoc, diag::err_template_parameter_default_friend_template)
|
||||||
|
<< DefArgRange;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// FIXME: C++0x [temp.param]p9 allows default template-arguments
|
||||||
|
// for friend function templates if there is only a single
|
||||||
|
// declaration (and it is a definition). Strange!
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Checks the validity of a template parameter list, possibly
|
/// \brief Checks the validity of a template parameter list, possibly
|
||||||
/// considering the template parameter list from a previous
|
/// considering the template parameter list from a previous
|
||||||
/// declaration.
|
/// declaration.
|
||||||
|
|
@ -1024,9 +1074,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||||
/// arguments will be merged from the old template parameter list to
|
/// arguments will be merged from the old template parameter list to
|
||||||
/// the new template parameter list.
|
/// the new template parameter list.
|
||||||
///
|
///
|
||||||
|
/// \param TPC Describes the context in which we are checking the given
|
||||||
|
/// template parameter list.
|
||||||
|
///
|
||||||
/// \returns true if an error occurred, false otherwise.
|
/// \returns true if an error occurred, false otherwise.
|
||||||
bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
TemplateParameterList *OldParams) {
|
TemplateParameterList *OldParams,
|
||||||
|
TemplateParamListContext TPC) {
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
|
|
||||||
// C++ [temp.param]p10:
|
// C++ [temp.param]p10:
|
||||||
|
|
@ -1066,9 +1120,17 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge default arguments for template type parameters.
|
|
||||||
if (TemplateTypeParmDecl *NewTypeParm
|
if (TemplateTypeParmDecl *NewTypeParm
|
||||||
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
|
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
|
||||||
|
// Check the presence of a default argument here.
|
||||||
|
if (NewTypeParm->hasDefaultArgument() &&
|
||||||
|
DiagnoseDefaultTemplateArgument(*this, TPC,
|
||||||
|
NewTypeParm->getLocation(),
|
||||||
|
NewTypeParm->getDefaultArgumentInfo()->getTypeLoc()
|
||||||
|
.getFullSourceRange()))
|
||||||
|
NewTypeParm->removeDefaultArgument();
|
||||||
|
|
||||||
|
// Merge default arguments for template type parameters.
|
||||||
TemplateTypeParmDecl *OldTypeParm
|
TemplateTypeParmDecl *OldTypeParm
|
||||||
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
|
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
|
||||||
|
|
||||||
|
|
@ -1098,6 +1160,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
MissingDefaultArg = true;
|
MissingDefaultArg = true;
|
||||||
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
|
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
|
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
|
||||||
|
// Check the presence of a default argument here.
|
||||||
|
if (NewNonTypeParm->hasDefaultArgument() &&
|
||||||
|
DiagnoseDefaultTemplateArgument(*this, TPC,
|
||||||
|
NewNonTypeParm->getLocation(),
|
||||||
|
NewNonTypeParm->getDefaultArgument()->getSourceRange())) {
|
||||||
|
NewNonTypeParm->getDefaultArgument()->Destroy(Context);
|
||||||
|
NewNonTypeParm->setDefaultArgument(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Merge default arguments for non-type template parameters
|
// Merge default arguments for non-type template parameters
|
||||||
NonTypeTemplateParmDecl *OldNonTypeParm
|
NonTypeTemplateParmDecl *OldNonTypeParm
|
||||||
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
|
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
|
||||||
|
|
@ -1124,9 +1195,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
} else if (SawDefaultArgument)
|
} else if (SawDefaultArgument)
|
||||||
MissingDefaultArg = true;
|
MissingDefaultArg = true;
|
||||||
} else {
|
} else {
|
||||||
// Merge default arguments for template template parameters
|
// Check the presence of a default argument here.
|
||||||
TemplateTemplateParmDecl *NewTemplateParm
|
TemplateTemplateParmDecl *NewTemplateParm
|
||||||
= cast<TemplateTemplateParmDecl>(*NewParam);
|
= cast<TemplateTemplateParmDecl>(*NewParam);
|
||||||
|
if (NewTemplateParm->hasDefaultArgument() &&
|
||||||
|
DiagnoseDefaultTemplateArgument(*this, TPC,
|
||||||
|
NewTemplateParm->getLocation(),
|
||||||
|
NewTemplateParm->getDefaultArgument().getSourceRange()))
|
||||||
|
NewTemplateParm->setDefaultArgument(TemplateArgumentLoc());
|
||||||
|
|
||||||
|
// Merge default arguments for template template parameters
|
||||||
TemplateTemplateParmDecl *OldTemplateParm
|
TemplateTemplateParmDecl *OldTemplateParm
|
||||||
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
|
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
|
||||||
if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
|
if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
|
||||||
|
|
@ -1299,6 +1377,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||||
ExpectedTemplateParams,
|
ExpectedTemplateParams,
|
||||||
true, TPL_TemplateMatch);
|
true, TPL_TemplateMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
|
||||||
} else if (ParamLists[Idx]->size() > 0)
|
} else if (ParamLists[Idx]->size() > 0)
|
||||||
Diag(ParamLists[Idx]->getTemplateLoc(),
|
Diag(ParamLists[Idx]->getTemplateLoc(),
|
||||||
diag::err_template_param_list_matches_nontemplate)
|
diag::err_template_param_list_matches_nontemplate)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
|
||||||
|
|
||||||
|
// A default template-argument shall not be specified in a function
|
||||||
|
// template declaration or a function template definition
|
||||||
|
template<typename T = int> // expected-error{{cannot have a default argument}}
|
||||||
|
void foo0(T);
|
||||||
|
template<typename T = int> // expected-error{{cannot have a default argument}}
|
||||||
|
void foo1(T) { }
|
||||||
|
|
||||||
|
// [...] nor in the template-parameter-list of the definition of a
|
||||||
|
// member of a class template.
|
||||||
|
template<int N>
|
||||||
|
struct X0 {
|
||||||
|
void f();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int N = 0> // expected-error{{cannot add a default template argument}}
|
||||||
|
void X0<N>::f() { }
|
||||||
|
|
||||||
|
class X1 {
|
||||||
|
template<template<int> class TT = X0> // expected-error{{not permitted on a friend template}}
|
||||||
|
friend void f2();
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue