Semantic checking for template arguments that correspond to non-type

template parameters that have reference type. Effectively, we're doing
a very limited form of reference binding here.

llvm-svn: 64270
This commit is contained in:
Douglas Gregor 2009-02-11 00:44:29 +00:00
parent 081e354f11
commit a9faa44162
3 changed files with 57 additions and 3 deletions

View File

@ -531,6 +531,11 @@ DIAG(err_template_arg_not_ice, ERROR,
"non-type template argument of type %0 is not an integral constant expression")
DIAG(err_template_arg_not_convertible, ERROR,
"non-type template argument of type %0 cannot be converted to a value of type %1")
DIAG(err_template_arg_no_ref_bind, ERROR,
"non-type template parameter of reference type %0 cannot bind to template argument of type %1")
DIAG(err_template_arg_ref_bind_ignores_quals, ERROR,
"reference binding of non-type template parameter of type %0 to template argument of type %1 ignores qualifiers")
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name %0: expected expression")

View File

@ -897,10 +897,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
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.
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);
@ -960,6 +960,43 @@ 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;
}
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;

View File

@ -67,3 +67,15 @@ A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded
// FIXME: expected-error{{expected unqualified-id}}
// FIXME: the first error includes the string <overloaded function
// type>, which makes Doug slightly unhappy.
struct Y { } y;
volatile X * X_volatile_ptr;
template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
A4<*X_ptr> *a15_1; // okay
A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} \
// FIXME: expected-error{{expected unqualified-id}}
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}}