]> granicus.if.org Git - clang/commitdiff
Semantic checking for template arguments that correspond to non-type
authorDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 00:44:29 +0000 (00:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 00:44:29 +0000 (00:44 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/temp_arg_nontype.cpp

index a4aa94982247a5057e711457239c9f716ddfcb5f..c58c0750a54d84debcf06dd10fe81689d36562d2 100644 (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")
index c78d8876dae1f50dac0a7dd351066d40dd3cc36b..d4ba0c5edba70646d021fc7162943428114309ae 100644 (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;
index 4b1db5ad687b2f5ec483a73bff20004e0442ac74..26ebb551e02078d61ffa2dffe9c8c0e3dea5695e 100644 (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}}
+