From: Chandler Carruth Date: Wed, 3 Feb 2010 09:37:33 +0000 (+0000) Subject: Fix PR6149 by looking at the qualifiers on the referred to type for non-type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5147fa6d580e4c123d0a90fa737f40824f50aa50;p=clang Fix PR6149 by looking at the qualifiers on the referred to type for non-type reference template arguments. Adds test cases for the cv-quals of reference arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95217 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 13cf783391..6a094e48e8 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2732,7 +2732,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) { + QualType ReferredType = ParamRefType->getPointeeType(); + if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_no_ref_bind) << InstantiatedParamType << Arg->getType() @@ -2742,7 +2743,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } unsigned ParamQuals - = Context.getCanonicalType(ParamType).getCVRQualifiers(); + = Context.getCanonicalType(ReferredType).getCVRQualifiers(); unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); if ((ParamQuals | ArgQuals) != ParamQuals) { diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp new file mode 100644 index 0000000000..6d1d39c33c --- /dev/null +++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// C++0x [temp.arg.nontype] p5: +// The following conversions are performed on each expression used as +// a non-type template-argument. If a non-type template-argument cannot be +// converted to the type of the corresponding template-parameter then the +// program is ill-formed. +// -- for a non-type template-parameter of integral or enumeration type, +// integral promotions (4.5) and integral conversions (4.7) are applied. +// -- 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 the template-argument is of type +// std::nullptr_t, the null pointer conversion (4.10) is applied. +// -- 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 shall be an lvalue. +namespace reference_parameters { + template struct S0 { }; // expected-note 3 {{template parameter is declared here}} + template struct S1 { }; // expected-note 2 {{template parameter is declared here}} + template struct S2 { }; // expected-note 2 {{template parameter is declared here}} + template struct S3 { }; + int i; + extern const int ci; + volatile int vi; + extern const volatile int cvi; + void test() { + S0 s0; + S0 s0c; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int const' ignores qualifiers}} + S0 s0v; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int volatile' ignores qualifiers}} + S0 s0cv; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int const volatile' ignores qualifiers}} + + S1 s1; + S1 s1c; + S1 s1v; // expected-error{{reference binding of non-type template parameter of type 'int const &' to template argument of type 'int volatile' ignores qualifiers}} + S1 s1cv; // expected-error{{reference binding of non-type template parameter of type 'int const &' to template argument of type 'int const volatile' ignores qualifiers}} + + S2 s2; + S2 s2c; // expected-error{{reference binding of non-type template parameter of type 'int volatile &' to template argument of type 'int const' ignores qualifiers}} + S2 s2v; + S2 s2cv; // expected-error{{reference binding of non-type template parameter of type 'int volatile &' to template argument of type 'int const volatile' ignores qualifiers}} + + S3 s3; + S3 s3c; + S3 s3v; + S3 s3cv; + } +} + +// -- For a non-type template-parameter of type pointer to function, the +// function-to-pointer conversion (4.3) is applied; if the +// template-argument is of type std::nullptr_t, the null pointer +// conversion (4.10) 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). +// -- 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). +// -- For a non-type template-parameter of type pointer to member function, +// if the template-argument is of type std::nullptr_t, the null member +// pointer conversion (4.11) is applied; otherwise, 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). +// -- For a non-type template-parameter of type pointer to data member, +// qualification conversions (4.4) are applied; if the template-argument +// is of type std::nullptr_t, the null member pointer conversion (4.11) +// is applied.