]> granicus.if.org Git - clang/commitdiff
Correct warning on Float->Integer conversions.
authorErich Keane <erich.keane@intel.com>
Mon, 7 May 2018 20:52:56 +0000 (20:52 +0000)
committerErich Keane <erich.keane@intel.com>
Mon, 7 May 2018 20:52:56 +0000 (20:52 +0000)
As identified and briefly discussed here:
https://bugs.llvm.org/show_bug.cgi?id=37305

Converting a floating point number to an integer type when
the integral part is out of the range of the integer type is
undefined behavior in C. Additionally, CodeGen emits an undef
in this situation.

HOWEVER, we've been giving a warning that says that the value is
changed. This patch corrects the warning to list that it is actually
undefined behavior.

Differential Revision: https://reviews.llvm.org/D46535

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaChecking.cpp
test/SemaCXX/coroutines.cpp
test/SemaCXX/warn-float-conversion.cpp
test/SemaCXX/warn-literal-conversion.cpp

index 03988a17e01ff9138d9db732cb45541875ad442d..a015f45feb414679f87395db050932e46fe40c20 100644 (file)
@@ -3140,6 +3140,9 @@ def warn_impcast_bitfield_precision_constant : Warning<
 def warn_impcast_literal_float_to_integer : Warning<
   "implicit conversion from %0 to %1 changes value from %2 to %3">,
   InGroup<LiteralConversion>;
+def warn_impcast_literal_float_to_integer_out_of_range : Warning<
+  "implicit conversion of out of range value from %0 to %1 is undefined">,
+  InGroup<LiteralConversion>;
 def warn_impcast_float_integer : Warning<
   "implicit conversion turns floating-point number into integer: %0 to %1">,
   InGroup<FloatConversion>, DefaultIgnore;
@@ -3148,6 +3151,9 @@ def warn_impcast_float_to_integer : Warning<
   "implicit conversion of out of range value from %0 to %1 changes value "
   "from %2 to %3">,
   InGroup<FloatOverflowConversion>, DefaultIgnore;
+def warn_impcast_float_to_integer_out_of_range : Warning<
+  "implicit conversion of out of range value from %0 to %1 is undefined">,
+  InGroup<FloatOverflowConversion>, DefaultIgnore;
 def warn_impcast_float_to_integer_zero : Warning<
   "implicit conversion from %0 to %1 changes non-zero value from %2 to %3">,
   InGroup<FloatZeroConversion>, DefaultIgnore;
index 8cc8330ea3a2b59620046a13320957dfeb476c23..9652b6e23a76992c809521ed2ef6201f0755f9cb 100644 (file)
@@ -9429,6 +9429,16 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
 
   unsigned DiagID = 0;
   if (IsLiteral) {
+    // Conversion of a floating-point value to a non-bool integer where the
+    // integral part cannot be represented by the integer type is undefined.
+    if (!IsBool &&
+        ((IntegerValue.isSigned() && (IntegerValue.isMaxSignedValue() ||
+                                      IntegerValue.isMinSignedValue())) ||
+         (IntegerValue.isUnsigned() &&
+          (IntegerValue.isMaxValue() || IntegerValue.isMinValue()))))
+      return DiagnoseImpCast(
+          S, E, T, CContext,
+          diag::warn_impcast_literal_float_to_integer_out_of_range);
     // Warn on floating point literal to integer.
     DiagID = diag::warn_impcast_literal_float_to_integer;
   } else if (IntegerValue == 0) {
@@ -9444,12 +9454,19 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
         return DiagnoseImpCast(S, E, T, CContext,
                                diag::warn_impcast_float_integer, PruneWarnings);
       }
+      if (!IsBool && (IntegerValue.isMaxValue() || IntegerValue.isMinValue()))
+        return DiagnoseImpCast(S, E, T, CContext,
+                               diag::warn_impcast_float_to_integer_out_of_range,
+                               PruneWarnings);
     } else {  // IntegerValue.isSigned()
       if (!IntegerValue.isMaxSignedValue() &&
           !IntegerValue.isMinSignedValue()) {
         return DiagnoseImpCast(S, E, T, CContext,
                                diag::warn_impcast_float_integer, PruneWarnings);
       }
+      return DiagnoseImpCast(S, E, T, CContext,
+                             diag::warn_impcast_float_to_integer_out_of_range,
+                             PruneWarnings);
     }
     // Warn on evaluatable floating point expression to integer conversion.
     DiagID = diag::warn_impcast_float_to_integer;
index 2c979f5b30d0d78de3b54ee0901939bb91596bd8..0d0588dbbf0029565e741fa1b89d468681df1439 100644 (file)
@@ -157,7 +157,7 @@ struct coroutine_handle<void> {
 void yield() {
   co_yield 0;
   co_yield {"foo", 1, 2};
-  co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}} expected-warning {{braces around scalar}}
+  co_yield {1e100}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{implicit conversion}} expected-warning {{braces around scalar}}
   co_yield {"foo", __LONG_LONG_MAX__}; // expected-error {{cannot be narrowed}} expected-note {{explicit cast}} expected-warning {{changes value}}
   co_yield {"foo"};
   co_yield "foo"; // expected-error {{no matching}}
index fc221893aeeea403f21ed5392670b76af5fa3a77..cf1ead038f392f75af1e56f70e49321def4eede4 100644 (file)
@@ -81,9 +81,9 @@ void TestOverflow() {
   char b = -500.0;  // caught by -Wliteral-conversion
 
   const float LargeNumber = 1024;
-  char c = LargeNumber;  // expected-warning{{implicit conversion of out of range value from 'const float' to 'char' changes value from 1024 to 127}}
-  char d = 400.0 + 400.0;  // expected-warning{{implicit conversion of out of range value from 'double' to 'char' changes value from 800 to 127}}
+  char c = LargeNumber;  // expected-warning{{implicit conversion of out of range value from 'const float' to 'char' is undefined}}
+  char d = 400.0 + 400.0;  // expected-warning{{implicit conversion of out of range value from 'double' to 'char' is undefined}}
 
-  char e = 1.0 / 0.0;  // expected-warning{{implicit conversion of out of range value from 'double' to 'char' changes value from +Inf to 127}}
+  char e = 1.0 / 0.0;  // expected-warning{{implicit conversion of out of range value from 'double' to 'char' is undefined}}
 }
 #endif  // OVERFLOW
index 875aa1dec5efd8441a9b1e98affdcbb049542bee..7efcf90fd963ef6c62fb1b92de07bce713feccff 100644 (file)
@@ -48,4 +48,11 @@ void test1() {
   // values.
   bool b3 = 0.0f;
   bool b4 = 0.0;
+
+  // These all warn because they overflow the target type.
+  short s = 32768.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'short' is undefined}}
+  unsigned short us = 65536.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'unsigned short' is undefined}}
+
+  short s2 = -32769.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'short' is undefined}}
+  unsigned short us2 = -65537.0; // expected-warning{{implicit conversion of out of range value from 'double' to 'unsigned short' is undefined}}
 }