[cfe-commits] r64277 - in /cfe/trunk: lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/temp_arg_nontype.cpp
Douglas Gregor
dgregor at apple.com
Tue Feb 10 17:18:59 PST 2009
Author: dgregor
Date: Tue Feb 10 19:18:59 2009
New Revision: 64277
URL: http://llvm.org/viewvc/llvm-project?rev=64277&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=64277&r1=64276&r2=64277&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Feb 10 19:18:59 2009
@@ -3952,6 +3952,25 @@
} 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)) {
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64277&r1=64276&r2=64277&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 10 19:18:59 2009
@@ -896,58 +896,45 @@
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 @@
return false;
}
+ 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");
+
+ 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()) {
- 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;
- }
+ // -- 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");
- 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;
- }
+ 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;
+ }
- // FIXME: Check the restrictions in p1!
- // CheckAddressConstantExpression(Lvalue) can be modified to do
- // this.
- return false;
+ 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;
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=64277&r1=64276&r2=64277&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Feb 10 19:18:59 2009
@@ -79,3 +79,26 @@
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}}
More information about the cfe-commits
mailing list