]> granicus.if.org Git - clang/commitdiff
Check for overflow and signedness problems with template
authorDouglas Gregor <dgregor@apple.com>
Sat, 14 Mar 2009 00:20:21 +0000 (00:20 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 14 Mar 2009 00:20:21 +0000 (00:20 +0000)
arguments. Eliminates a FIXME.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66993 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 8938a7ae63074e8768c3121a5026452811f25f5f..be17a9746ddd1261c8de11e75cc57ab1bc88dc91 100644 (file)
@@ -604,6 +604,12 @@ 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_negative, ERROR,
+     "non-type template argument provides negative value '%0' for unsigned "
+     "template parameter of type %1")
+DIAG(err_template_arg_too_large, ERROR,
+     "non-type template argument value '%0' is too large for template "
+     "parameter 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,
index 142cc453f363579efdab92ce3c4e6549e612e07e..fd1eaf0ace62a9d81a67336b50505f8aba26177a 100644 (file)
@@ -1266,16 +1266,42 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
       return true;
     }
 
-    // FIXME: Check overflow of template arguments?
+    QualType IntegerType = Context.getCanonicalType(ParamType);
+    if (const EnumType *Enum = IntegerType->getAsEnumType())
+      IntegerType = Enum->getDecl()->getIntegerType();
+
+    if (!Arg->isValueDependent()) {
+      // Check that an unsigned parameter does not receive a negative
+      // value.
+      if (IntegerType->isUnsignedIntegerType()
+          && (Value.isSigned() && Value.isNegative())) {
+        Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative)
+          << Value.toString(10) << Param->getType()
+          << Arg->getSourceRange();
+        Diag(Param->getLocation(), diag::note_template_param_here);
+        return true;
+      }
+
+      // Check that we don't overflow the template parameter type.
+      unsigned AllowedBits = Context.getTypeSize(IntegerType);
+      if (Value.getActiveBits() > AllowedBits) {
+        Diag(Arg->getSourceRange().getBegin(), 
+             diag::err_template_arg_too_large)
+          << Value.toString(10) << Param->getType()
+          << Arg->getSourceRange();
+        Diag(Param->getLocation(), diag::note_template_param_here);
+        return true;
+      }
+
+      if (Value.getBitWidth() != AllowedBits)
+        Value.extOrTrunc(AllowedBits);
+      Value.setIsSigned(IntegerType->isSignedIntegerType());
+    }
 
     if (Converted) {
       // Add the value of this argument to the list of converted
       // arguments. We use the bitwidth and signedness of the template
       // parameter.
-      QualType IntegerType = Context.getCanonicalType(ParamType);
-      if (const EnumType *Enum = IntegerType->getAsEnumType())
-        IntegerType = Enum->getDecl()->getIntegerType();
-
       if (Arg->isValueDependent()) {
         // The argument is value-dependent. Create a new
         // TemplateArgument with the converted expression.
@@ -1283,11 +1309,6 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
         return false;
       } 
 
-      unsigned ExpectedBits = Context.getTypeSize(IntegerType);
-      if (Value.getBitWidth() != ExpectedBits)
-        Value.extOrTrunc(ExpectedBits);
-      Value.setIsSigned(IntegerType->isSignedIntegerType());
-
       Converted->push_back(TemplateArgument(StartLoc, Value,
                                    Context.getCanonicalType(IntegerType)));
     }
index 55815fce1faaabc3a585967527996e5f2f42572c..381947269e99b7d0f2d8c665a51ed18da047a00d 100644 (file)
@@ -102,3 +102,13 @@ A7<&Z::int_member> *a18_1;
 A7c<&Z::int_member> *a18_2;
 A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}}
 A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
+
+template<unsigned char C> struct Overflow; // expected-note{{template parameter is declared here}}
+
+Overflow<5> *overflow1; // okay
+Overflow<256> *overflow2; // expected-error{{non-type template argument value '256' is too large for template parameter of type 'unsigned char'}}
+
+
+template<unsigned> struct Signedness; // expected-note{{template parameter is declared here}}
+Signedness<10> *signedness1; // okay
+Signedness<-10> *signedness2; // expected-error{{non-type template argument provides negative value '-10' for unsigned template parameter of type 'unsigned int'}}