зеркало из https://github.com/microsoft/clang-1.git
Add semantic checking for template arguments that correspond to
non-type template parameters that are references to functions or pointers to member functions. Did a little bit of refactoring so that these two cases, along with the handling of non-type template parameters that are pointers to functions, are handled by the same path. Also, tweaked FixOverloadedFunctionReference to cope with member function pointers. This is a necessary step for getting all of the fun member pointer conversions working outside of template arguments, too. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64277 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
77a60115e3
Коммит
b86b0579c5
|
@ -3952,6 +3952,25 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
|
|||
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
|
||||
assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
|
||||
"Can only take the address of an overloaded function");
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
|
||||
if (Method->isStatic()) {
|
||||
// Do nothing: static member functions aren't any different
|
||||
// from non-member functions.
|
||||
}
|
||||
else if (QualifiedDeclRefExpr *DRE
|
||||
= dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) {
|
||||
// We have taken the address of a pointer to member
|
||||
// function. Perform the computation here so that we get the
|
||||
// appropriate pointer to member type.
|
||||
DRE->setDecl(Fn);
|
||||
DRE->setType(Fn->getType());
|
||||
QualType ClassType
|
||||
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
|
||||
E->setType(Context.getMemberPointerType(Fn->getType(),
|
||||
ClassType.getTypePtr()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
|
||||
E->setType(Context.getPointerType(UnOp->getSubExpr()->getType()));
|
||||
} else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
|
||||
|
|
|
@ -896,58 +896,45 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
|
||||
if (ParamPtrType->getPointeeType()->isObjectType()) {
|
||||
// -- for a non-type template-parameter of type pointer to
|
||||
// object, qualification conversions (4.4) and the
|
||||
// array-to-pointer conversion (4.2) are applied.
|
||||
if (ArgType->isArrayType()) {
|
||||
ArgType = Context.getArrayDecayedType(ArgType);
|
||||
ImpCastExprToType(Arg, ArgType);
|
||||
}
|
||||
|
||||
if (IsQualificationConversion(ArgType, ParamType)) {
|
||||
ArgType = ParamType;
|
||||
ImpCastExprToType(Arg, ParamType);
|
||||
}
|
||||
|
||||
if (!hasSameUnqualifiedType(ArgType, ParamType)) {
|
||||
// We can't perform this conversion.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_convertible)
|
||||
<< Arg->getType() << Param->getType() << Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(ParamPtrType->getPointeeType()->isFunctionType() &&
|
||||
"Only function pointers remain");
|
||||
// -- For a non-type template-parameter of type pointer to
|
||||
// function, only the function-to-pointer conversion (4.3) is
|
||||
// applied. If the template-argument represents a set of
|
||||
// overloaded functions (or a pointer to such), the matching
|
||||
// function is selected from the set (13.4).
|
||||
if (hasSameUnqualifiedType(ArgType, ParamType)) {
|
||||
// Handle pointer-to-function, reference-to-function, and
|
||||
// pointer-to-member-function all in (roughly) the same way.
|
||||
if (// -- For a non-type template-parameter of type pointer to
|
||||
// function, only the function-to-pointer conversion (4.3) is
|
||||
// applied. If the template-argument represents a set of
|
||||
// overloaded functions (or a pointer to such), the matching
|
||||
// function is selected from the set (13.4).
|
||||
(ParamType->isPointerType() &&
|
||||
ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) ||
|
||||
// -- For a non-type template-parameter of type reference to
|
||||
// function, no conversions apply. If the template-argument
|
||||
// represents a set of overloaded functions, the matching
|
||||
// function is selected from the set (13.4).
|
||||
(ParamType->isReferenceType() &&
|
||||
ParamType->getAsReferenceType()->getPointeeType()->isFunctionType()) ||
|
||||
// -- For a non-type template-parameter of type pointer to
|
||||
// member function, no conversions apply. If the
|
||||
// template-argument represents a set of overloaded member
|
||||
// functions, the matching member function is selected from
|
||||
// the set (13.4).
|
||||
(ParamType->isMemberPointerType() &&
|
||||
ParamType->getAsMemberPointerType()->getPointeeType()
|
||||
->isFunctionType())) {
|
||||
if (hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) {
|
||||
// We don't have to do anything: the types already match.
|
||||
}
|
||||
else if (ArgType->isFunctionType()) {
|
||||
} else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
|
||||
ArgType = Context.getPointerType(ArgType);
|
||||
ImpCastExprToType(Arg, ArgType);
|
||||
} else if (FunctionDecl *Fn
|
||||
= ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
|
||||
FixOverloadedFunctionReference(Arg, Fn);
|
||||
ArgType = Arg->getType();
|
||||
if (ArgType->isFunctionType()) {
|
||||
if (ArgType->isFunctionType() && ParamType->isPointerType()) {
|
||||
ArgType = Context.getPointerType(Arg->getType());
|
||||
ImpCastExprToType(Arg, ArgType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSameUnqualifiedType(ArgType, ParamType)) {
|
||||
if (!hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) {
|
||||
// We can't perform this conversion.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_convertible)
|
||||
|
@ -960,43 +947,73 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
|
||||
if (ParamRefType->getPointeeType()->isObjectType()) {
|
||||
// -- For a non-type template-parameter of type reference to
|
||||
// object, no conversions apply. The type referred to by the
|
||||
// reference may be more cv-qualified than the (otherwise
|
||||
// identical) type of the template-argument. The
|
||||
// template-parameter is bound directly to the
|
||||
// template-argument, which must be an lvalue.
|
||||
if (!hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_no_ref_bind)
|
||||
<< Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
|
||||
// -- for a non-type template-parameter of type pointer to
|
||||
// object, qualification conversions (4.4) and the
|
||||
// array-to-pointer conversion (4.2) are applied.
|
||||
assert(ParamPtrType->getPointeeType()->isObjectType() &&
|
||||
"Only object pointers allowed here");
|
||||
|
||||
unsigned ParamQuals
|
||||
= Context.getCanonicalType(ParamType).getCVRQualifiers();
|
||||
unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
|
||||
|
||||
if ((ParamQuals | ArgQuals) != ParamQuals) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_ref_bind_ignores_quals)
|
||||
<< Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
// CheckAddressConstantExpression(Lvalue) can be modified to do
|
||||
// this.
|
||||
return false;
|
||||
if (ArgType->isArrayType()) {
|
||||
ArgType = Context.getArrayDecayedType(ArgType);
|
||||
ImpCastExprToType(Arg, ArgType);
|
||||
}
|
||||
|
||||
if (IsQualificationConversion(ArgType, ParamType)) {
|
||||
ArgType = ParamType;
|
||||
ImpCastExprToType(Arg, ParamType);
|
||||
}
|
||||
|
||||
if (!hasSameUnqualifiedType(ArgType, ParamType)) {
|
||||
// We can't perform this conversion.
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_not_convertible)
|
||||
<< Arg->getType() << Param->getType() << Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
|
||||
// -- For a non-type template-parameter of type reference to
|
||||
// object, no conversions apply. The type referred to by the
|
||||
// reference may be more cv-qualified than the (otherwise
|
||||
// identical) type of the template-argument. The
|
||||
// template-parameter is bound directly to the
|
||||
// template-argument, which must be an lvalue.
|
||||
assert(ParamRefType->getPointeeType()->isObjectType() &&
|
||||
"Only object references allowed here");
|
||||
|
||||
if (!hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_no_ref_bind)
|
||||
<< Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned ParamQuals
|
||||
= Context.getCanonicalType(ParamType).getCVRQualifiers();
|
||||
unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
|
||||
|
||||
if ((ParamQuals | ArgQuals) != ParamQuals) {
|
||||
Diag(Arg->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_ref_bind_ignores_quals)
|
||||
<< Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Check the restrictions in p1!
|
||||
// CheckAddressConstantExpression(Lvalue) can be modified to do
|
||||
// this.
|
||||
return false;
|
||||
}
|
||||
// FIXME: p5 has a lot more checks to perform!
|
||||
|
||||
return false;
|
||||
|
|
|
@ -79,3 +79,26 @@ A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type tem
|
|||
A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}}\
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
|
||||
template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
|
||||
A5<h> *a16_1;
|
||||
A5<(h)> *a16_2;
|
||||
A5<f> *a16_3;
|
||||
A5<(f)> *a16_4;
|
||||
A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}\
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
// FIXME: the first error includes the string <overloaded function
|
||||
// type>, which makes Doug slightly unhappy.
|
||||
|
||||
struct Z {
|
||||
int foo(int);
|
||||
float bar(float);
|
||||
int bar(int);
|
||||
double baz(double);
|
||||
};
|
||||
template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}}
|
||||
A6<&Z::foo> *a17_1;
|
||||
A6<&Z::bar> *a17_2;
|
||||
A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} \
|
||||
// FIXME: expected-error{{expected unqualified-id}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче