]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c/53001 (-Wfloat-conversion should be available to warn about floating point...
authorJoshua J Cogliati <jrincayc@yahoo.com>
Wed, 20 Nov 2013 07:15:40 +0000 (07:15 +0000)
committerManuel López-Ibáñez <manu@gcc.gnu.org>
Wed, 20 Nov 2013 07:15:40 +0000 (07:15 +0000)
2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>

PR c/53001
Splitting out a -Wfloat-conversion from -Wconversion for
conversions that lower floating point number precision
or conversion from floating point numbers to integers.

gcc/c-family/

* c-common.c (unsafe_conversion_p): Make this function
return an enumeration with more detail.
(conversion_warning): Use the new return type of
unsafe_conversion_p to separately warn either about conversions
that lower floating point number precision or about the other
kinds of conversions.
  * c-common.h (enum conversion_safety): New enumeration.
  (unsafe_conversion_p): switching return type to
  conversion_safety enumeration.
* c.opt: Adding new warning -Wfloat-conversion and
enabling it with -Wconversion.

gcc/

* doc/invoke.texi: Adding documentation about
-Wfloat-conversion.

gcc/testsuite/

* c-c++-common/Wfloat-conversion.c: Copies relevant
tests from c-c++-common/Wconversion-real.c,
gcc.dg/Wconversion-real-integer.c and gcc.dg/pr35635.c into
new testcase for conversions that are warned about by
-Wfloat-conversion.

From-SVN: r205090

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c.opt
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wfloat-conversion.c [new file with mode: 0644]

index dd15cd4d292e4f9162f746ba0b56c4a4ede8ce0f..3900adfd66c929b3fc2fc0b84715812297e34e98 100644 (file)
@@ -1,3 +1,9 @@
+2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>
+
+       PR c/53001
+       * doc/invoke.texi: Adding documentation about
+       -Wfloat-conversion.
+
 2013-11-20  Miro Kropacek  <miro.kropacek@gmail.com>
 
        * config/m68k/m68k.c (m68k_option_overrides): Fix typo.
index 5bbd5f5c5efd3e20cbc24c392e0efc78b8020fec..525efad325b58077889f85e4ca392129d7cfae41 100644 (file)
@@ -1,3 +1,18 @@
+2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>
+
+       PR c/53001
+       * c-common.c (unsafe_conversion_p): Make this function
+       return an enumeration with more detail.
+       (conversion_warning): Use the new return type of
+       unsafe_conversion_p to separately warn either about conversions
+       that lower floating point number precision or about the other
+       kinds of conversions.
+       * c-common.h (enum conversion_safety): New enumeration.
+       (unsafe_conversion_p): switching return type to
+       conversion_safety enumeration.
+       * c.opt: Adding new warning -Wfloat-conversion and
+       enabling it with -Wconversion.
+
 2013-11-19  Basile Starynkevitch  <basile@starynkevitch.net>
 
         * c-opts.c: Include plugin.h.
index b4bd63ba213b1afa4f68dadb3f7dc68ba559cb99..9f89a161b1484ee870ce6d9ddfeb278cbbc84196 100644 (file)
@@ -2537,7 +2537,7 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
 }
 
 /* Checks if expression EXPR of real/integer type cannot be converted 
-   to the real/integer type TYPE. Function returns true when:
+   to the real/integer type TYPE. Function returns non-zero when:
        * EXPR is a constant which cannot be exactly converted to TYPE 
        * EXPR is not a constant and size of EXPR's type > than size of TYPE, 
          for EXPR type and TYPE being both integers or both real.
@@ -2545,12 +2545,12 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
        * EXPR is not a constant of integer type which cannot be 
          exactly converted to real type.  
    Function allows conversions between types of different signedness and
-   does not return true in that case.  Function can produce signedness
-   warnings if PRODUCE_WARNS is true.  */
-bool
+   can return SAFE_CONVERSION (zero) in that case.  Function can produce
+   signedness warnings if PRODUCE_WARNS is true.  */
+enum conversion_safety
 unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 {
-  bool give_warning = false;
+  enum conversion_safety give_warning = SAFE_CONVERSION; /* is 0 or false */
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
@@ -2562,7 +2562,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
          && TREE_CODE (type) == INTEGER_TYPE)
        {
          if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
-           give_warning = true;
+           give_warning = UNSAFE_REAL;
        }
       /* Warn for an integer constant that does not fit into integer type.  */
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
@@ -2583,7 +2583,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
                            " constant value to negative integer");
            }
          else
-           give_warning = true;
+           give_warning = UNSAFE_OTHER;
        }
       else if (TREE_CODE (type) == REAL_TYPE)
        {
@@ -2592,7 +2592,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
            {
              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
              if (!exact_real_truncate (TYPE_MODE (type), &a))
-               give_warning = true;
+               give_warning = UNSAFE_REAL;
            }
          /* Warn for a real constant that does not fit into a smaller
             real type.  */
@@ -2601,7 +2601,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
            {
              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
              if (!exact_real_truncate (TYPE_MODE (type), &a))
-               give_warning = true;
+               give_warning = UNSAFE_REAL;
            }
        }
     }
@@ -2610,7 +2610,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
       /* Warn for real types converted to integer types.  */
       if (TREE_CODE (expr_type) == REAL_TYPE
          && TREE_CODE (type) == INTEGER_TYPE)
-       give_warning = true;
+       give_warning = UNSAFE_REAL;
 
       else if (TREE_CODE (expr_type) == INTEGER_TYPE
               && TREE_CODE (type) == INTEGER_TYPE)
@@ -2648,7 +2648,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
                          && int_fits_type_p (op1, c_common_signed_type (type))
                          && int_fits_type_p (op1,
                                              c_common_unsigned_type (type))))
-                   return false;
+                   return SAFE_CONVERSION;
                  /* If constant is unsigned and fits in the target
                     type, then the result will also fit.  */
                  else if ((TREE_CODE (op0) == INTEGER_CST
@@ -2657,12 +2657,12 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
                           || (TREE_CODE (op1) == INTEGER_CST
                               && unsigned1
                               && int_fits_type_p (op1, type)))
-                   return false;
+                   return SAFE_CONVERSION;
                }
            }
          /* Warn for integer types converted to smaller integer types.  */
          if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-           give_warning = true;
+           give_warning = UNSAFE_OTHER;
 
          /* When they are the same width but different signedness,
             then the value may change.  */
@@ -2698,14 +2698,14 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
 
          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
-           give_warning = true;
+           give_warning = UNSAFE_OTHER;
        }
 
       /* Warn for real types converted to smaller real types.  */
       else if (TREE_CODE (expr_type) == REAL_TYPE
               && TREE_CODE (type) == REAL_TYPE
               && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
-       give_warning = true;
+       give_warning = UNSAFE_REAL;
     }
 
   return give_warning;
@@ -2719,8 +2719,9 @@ conversion_warning (tree type, tree expr)
 {
   tree expr_type = TREE_TYPE (expr);
   location_t loc = EXPR_LOC_OR_HERE (expr);
+  enum conversion_safety conversion_kind;
 
-  if (!warn_conversion && !warn_sign_conversion)
+  if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
     return;
 
   switch (TREE_CODE (expr))
@@ -2747,7 +2748,12 @@ conversion_warning (tree type, tree expr)
 
     case REAL_CST:
     case INTEGER_CST:
-      if (unsafe_conversion_p (type, expr, true))
+      conversion_kind = unsafe_conversion_p (type, expr, true);
+      if (conversion_kind == UNSAFE_REAL)
+       warning_at (loc, OPT_Wfloat_conversion,
+                   "conversion to %qT alters %qT constant value",
+                   type, expr_type);
+      else if (conversion_kind)
        warning_at (loc, OPT_Wconversion,
                    "conversion to %qT alters %qT constant value",
                    type, expr_type);
@@ -2766,7 +2772,12 @@ conversion_warning (tree type, tree expr)
       }
 
     default: /* 'expr' is not a constant.  */
-      if (unsafe_conversion_p (type, expr, true))
+      conversion_kind = unsafe_conversion_p (type, expr, true);
+      if (conversion_kind == UNSAFE_REAL)
+       warning_at (loc, OPT_Wfloat_conversion,
+                   "conversion to %qT from %qT may alter its value",
+                   type, expr_type);
+      else if (conversion_kind)
        warning_at (loc, OPT_Wconversion,
                    "conversion to %qT from %qT may alter its value",
                    type, expr_type);
index b931fd6d2a8625b671ca366bc767780eff7c0da7..664e9287a1b43ddd09da777e537f00a8aac5ad91 100644 (file)
@@ -688,6 +688,16 @@ struct visibility_flags
   unsigned inlines_hidden : 1; /* True when -finlineshidden in effect.  */
 };
 
+/* These enumerators are possible types of unsafe conversions.
+   SAFE_CONVERSION The conversion is safe
+   UNSAFE_OTHER Another type of conversion with problems
+   UNSAFE_SIGN Conversion between signed and unsigned integers
+    which are all warned about immediately, so this is unused
+   UNSAFE_REAL Conversions that reduce the precision of reals
+    including conversions from reals to integers
+ */
+enum conversion_safety { SAFE_CONVERSION = 0, UNSAFE_OTHER, UNSAFE_SIGN, UNSAFE_REAL };
+
 /* Global visibility options.  */
 extern struct visibility_flags visibility_options;
 
@@ -741,7 +751,7 @@ extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
 extern void c_common_init_ts (void);
 extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
-extern bool unsafe_conversion_p (tree, tree, bool);
+extern enum conversion_safety unsafe_conversion_p (tree, tree, bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
 extern tree decl_constant_value_for_optimization (tree);
index 0026683730e1f9b4b450e7aff0cb772514c5ee32..ac6788554148961596b52bba32bdf1da70be8075 100644 (file)
@@ -387,6 +387,10 @@ Werror-implicit-function-declaration
 C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration)
 This switch is deprecated; use -Werror=implicit-function-declaration instead
 
+Wfloat-conversion
+C ObjC C++ ObjC++ Var(warn_float_conversion) LangEnabledBy(C ObjC C++ ObjC++,Wconversion)
+Warn for implicit type conversions that cause loss of floating point precision
+
 Wfloat-equal
 C ObjC C++ ObjC++ Var(warn_float_equal) Warning
 Warn if testing floating point numbers for equality
index 7074a48cbf519c1e07d52e47c0b780e1f9f341a2..6fc56b92aada043f9730b3f0831271e8f031a77a 100644 (file)
@@ -262,7 +262,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wpointer-arith  -Wno-pointer-to-int-cast @gol
 -Wredundant-decls  -Wno-return-local-addr @gol
 -Wreturn-type  -Wsequence-point  -Wshadow @gol
--Wsign-compare  -Wsign-conversion  -Wsizeof-pointer-memaccess @gol
+-Wsign-compare  -Wsign-conversion -Wfloat-conversion @gol
+-Wsizeof-pointer-memaccess @gol
 -Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
@@ -4592,6 +4593,14 @@ value, like assigning a signed integer expression to an unsigned
 integer variable. An explicit cast silences the warning. In C, this
 option is enabled also by @option{-Wconversion}.
 
+@item -Wfloat-conversion
+@opindex Wfloat-conversion
+@opindex Wno-float-conversion
+Warn for implicit conversions that reduce the precision of a real value.
+This includes conversions from real to integer, and from higher precision
+real to lower precision real values.  This option is also enabled by
+@option{-Wconversion}.
+
 @item -Wsizeof-pointer-memaccess
 @opindex Wsizeof-pointer-memaccess
 @opindex Wno-sizeof-pointer-memaccess
index 178dd39d5a455e201d6d91144e6c6ddcd60ebbe6..bb30fd36e6ae622aa5e746cbedc3a3e49cfee6de 100644 (file)
@@ -1,3 +1,12 @@
+2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>
+
+       PR c/53001
+       * c-c++-common/Wfloat-conversion.c: Copies relevant
+       tests from c-c++-common/Wconversion-real.c,
+       gcc.dg/Wconversion-real-integer.c and gcc.dg/pr35635.c into
+       new testcase for conversions that are warned about by
+       -Wfloat-conversion.
+
 2013-11-19  Martin Jambor  <mjambor@suse.cz>
 
        PR rtl-optimization/59099
diff --git a/gcc/testsuite/c-c++-common/Wfloat-conversion.c b/gcc/testsuite/c-c++-common/Wfloat-conversion.c
new file mode 100644 (file)
index 0000000..e872755
--- /dev/null
@@ -0,0 +1,58 @@
+/* Test for diagnostics for Wconversion for floating-point.  */
+
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -Wfloat-conversion" { target c } } */
+/* { dg-options "-Wfloat-conversion" { target c++ } } */
+/* { dg-require-effective-target large_double } */
+/* { dg-require-effective-target int32plus } */
+/* { dg-require-effective-target double64plus } */
+#include <limits.h>
+
+float  vfloat;
+double vdouble;
+long double vlongdouble;
+int bar;
+
+void fsi (signed int x);
+void fui (unsigned int x);
+void ffloat (float f);
+void fdouble (double d);
+void flongdouble (long double ld);
+
+void h (void)
+{
+  unsigned int ui = 3;
+  int   si = 3;
+  unsigned char uc = 3;
+  signed char sc = 3;
+  float f = 0;
+  double d = 0;
+  long double ld = 0;
+
+  ffloat (3.1); /* { dg-warning "conversion to 'float' alters 'double' constant value" } */
+  vfloat = 3.1; /* { dg-warning "conversion to 'float' alters 'double' constant value" } */
+  ffloat (3.1L); /* { dg-warning "conversion to 'float' alters 'long double' constant value" } */
+  vfloat = 3.1L;  /* { dg-warning "conversion to 'float' alters 'long double' constant value" } */
+  fdouble (3.1L); /* { dg-warning "conversion to 'double' alters 'long double' constant value" "" { target large_long_double } } */
+  vdouble = 3.1L; /* { dg-warning "conversion to 'double' alters 'long double' constant value" "" { target large_long_double } } */
+  ffloat (vdouble); /* { dg-warning "conversion to 'float' from 'double' may alter its value" } */
+  vfloat = vdouble; /* { dg-warning "conversion to 'float' from 'double' may alter its value" } */
+  ffloat (vlongdouble); /* { dg-warning "conversion to 'float' from 'long double' may alter its value" } */
+  vfloat = vlongdouble; /* { dg-warning "conversion to 'float' from 'long double' may alter its value" } */
+  fdouble (vlongdouble); /* { dg-warning "conversion to 'double' from 'long double' may alter its value" "" { target large_long_double } } */
+  vdouble = vlongdouble; /* { dg-warning "conversion to 'double' from 'long double' may alter its value" "" { target large_long_double } } */
+
+  fsi (3.1f); /* { dg-warning "conversion to 'int' alters 'float' constant value" } */
+  si = 3.1f; /* { dg-warning "conversion to 'int' alters 'float' constant value" } */
+  fsi (3.1);  /* { dg-warning "conversion to 'int' alters 'double' constant value" } */
+  si = 3.1;  /* { dg-warning "conversion to 'int' alters 'double' constant value" } */
+  fsi (d);    /* { dg-warning "conversion to 'int' from 'double' may alter its value" } */
+  si = d;    /* { dg-warning "conversion to 'int' from 'double' may alter its value" } */
+  ffloat (INT_MAX);  /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
+  vfloat = INT_MAX;  /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
+  ffloat (16777217); /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
+  vfloat = 16777217; /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
+
+  sc = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion to 'signed char' alters 'double' constant value" } */
+  uc = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion to 'unsigned char' alters 'double' constant value" } */
+}