From: Douglas Gregor Date: Wed, 11 Feb 2009 00:44:29 +0000 (+0000) Subject: Semantic checking for template arguments that correspond to non-type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f684e6e793a336f52138a2609b207e6eef3c3022;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64270 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index a4aa949822..c58c0750a5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -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") diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c78d8876da..d4ba0c5edb 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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; diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 4b1db5ad68..26ebb551e0 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -67,3 +67,15 @@ A3 *a14_7; // expected-error{{non-type template argument of type ', which makes Doug slightly unhappy. + + +struct Y { } y; + +volatile X * X_volatile_ptr; +template 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 *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}} +