This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] [3of5] looking for feedback on Wcoercion warning (for stage1)


(The following patch implements part of the functionality of the
Wcoercion project as explained in
http://gcc.gnu.org/wiki/Wcoercion#Background ).

This patch adds the new functionality and testcases: Warn for implicit
conversions that may alter a value. This includes conversions caused
by function prototypes like abs(x) when
x is real and by assignments like unsigned x = -1. Do not warn about
explicit casts like
abs((int)x) and x = (unsigned) -1, or if the value is not changed by
the conversion like abs(2.0).

This is the second of a series of 5 patches. The previous patch can be
found at  http://gcc.gnu.org/ml/gcc-patches/2006-08/msg00246.html .

Bootstrapped and tested with --enable-languages=all for trunk revision
115951 on i686-pc-linux-gnu

:ADDPATCH c/c++:
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/c-common.c 3of3-coercion_warning/gcc/c-common.c
--- 2of3-real_isinteger/gcc/c-common.c	2006-08-07 20:32:59.000000000 +0100
+++ 3of3-coercion_warning/gcc/c-common.c	2006-08-07 18:43:07.000000000 +0100
@@ -1067,6 +1067,109 @@ vector_types_convertible_p (tree t1, tre
 		== INTEGRAL_TYPE_P (TREE_TYPE (t2)));
 }
 
+/* Warns if the conversion of EXPR to TYPE may alter a value.
+   This function is called from convert_and_check().  */
+
+void
+coercion_warning (tree type, tree expr)
+{
+  bool give_warning = false;
+
+  unsigned int formal_prec = TYPE_PRECISION (type);
+
+  if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
+    {
+      /* Warn for real constant that is not an exact integer coerced
+         to integer type.  */
+      if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+          && TREE_CODE (type) == INTEGER_TYPE
+          && !real_isinteger (TREE_REAL_CST (expr), TYPE_MODE (TREE_TYPE (expr))))
+        give_warning = true;
+
+      /* Warn for an integer constant that does not fit into integer
+         type. However, warnings for negative constants coerced to
+         unsigned types are detected by unsigned_conversion_warning.  */
+      else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+               && TREE_CODE (type) == INTEGER_TYPE
+               && !int_fits_type_p (expr, type)
+               && !(TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
+        give_warning = true;
+
+      else if (TREE_CODE (type) == REAL_TYPE)
+        {
+          if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+            {
+              REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
+              if (!exact_real_truncate (TYPE_MODE (type), &a))
+                give_warning = true;
+            }
+          else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+                   && formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+            {
+              REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
+              if (!exact_real_truncate (TYPE_MODE (type), &a))
+                give_warning = true;
+            }
+        }
+
+      if (give_warning)
+        warning (OPT_Wcoercion,
+                 "coercion as %qT alters %qT constant value",
+                 type, TREE_TYPE (expr));
+    }
+  else /* 'expr' is not a constant.  */
+    {
+      /* Warn for real types coerced to integer types.  */
+      if (TREE_CODE (type) == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+        give_warning = true;
+
+      /* Warn for integer types coerced to real types if and only if
+         all the range of values of the integer type cannot be
+         represented by the real type.  */
+      else if (TREE_CODE (type) == REAL_TYPE
+               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+        {
+          tree type_low_bound = TYPE_MIN_VALUE (TREE_TYPE (expr));
+          tree type_high_bound = TYPE_MAX_VALUE (TREE_TYPE (expr));
+          REAL_VALUE_TYPE real_low_bound = real_value_from_int_cst (0, type_low_bound);
+          REAL_VALUE_TYPE real_high_bound = real_value_from_int_cst (0, type_high_bound);
+
+          if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
+              || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
+            give_warning = true;
+        }
+
+      /* Warn for real types coerced to smaller real types.  */
+      else if (TREE_CODE (type) == REAL_TYPE
+               && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+               && formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+        give_warning = true;
+
+
+      else if (TREE_CODE  (type) == INTEGER_TYPE
+               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE)
+        {
+          /* Warn for integer types coerced to smaller integer types.  */
+          if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))
+              /* When they are the same width but different signedness,
+                 then the value may change.  */
+              || (formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
+                  && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
+              /* Even when coerced to a bigger type, if the type is
+                 unsigned but expr is signed, then negative values
+                 will be changed.  */
+              || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
+            give_warning = true;
+        }
+
+      if (give_warning)
+        warning (OPT_Wcoercion,
+                 "coercion to %qT from %qT may alter its value",
+                 type, TREE_TYPE (expr));
+    }
+}
+
 /* Convert EXPR to TYPE, warning about conversion problems with constants.
    Invoke this function on every expression that is converted implicitly,
    i.e. because of language rules and not because of an explicit cast.  */
@@ -1074,7 +1177,12 @@ vector_types_convertible_p (tree t1, tre
 tree
 convert_and_check (tree type, tree expr)
 {
-  tree t = convert (type, expr);
+  tree t;
+
+  if (warn_coercion && !skip_evaluation)
+    coercion_warning (type, expr);
+
+  t = convert (type, expr);
   if (TREE_CODE (t) == INTEGER_CST)
     {
       if (TREE_OVERFLOW (t))
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/c-common.h 3of3-coercion_warning/gcc/c-common.h
--- 2of3-real_isinteger/gcc/c-common.h	2006-08-05 18:05:47.000000000 +0100
+++ 3of3-coercion_warning/gcc/c-common.h	2006-08-05 18:06:01.000000000 +0100
@@ -656,6 +656,7 @@ struct varray_head_tag;
 extern void constant_expression_warning (tree);
 extern void strict_aliasing_warning(tree, tree, tree);
 extern void empty_body_warning (tree, tree);
+extern void coercion_warning (tree type, tree expr);
 extern tree convert_and_check (tree, tree);
 extern void overflow_warning (tree);
 extern bool c_determine_visibility (tree);
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/doc/invoke.texi 3of3-coercion_warning/gcc/doc/invoke.texi
--- 2of3-real_isinteger/gcc/doc/invoke.texi	2006-08-07 20:34:24.000000000 +0100
+++ 3of3-coercion_warning/gcc/doc/invoke.texi	2006-08-07 20:35:34.000000000 +0100
@@ -3124,10 +3124,12 @@ except when the same as the default prom
 
 @item -Wcoercion
 @opindex Wcoercion
-Warn if a negative integer constant expression is implicitly converted
-to an unsigned type.  For example, warn about the assignment
-@code{unsigned x = -1} if @code{x} is unsigned. But do not warn about
-explicit casts like @code{(unsigned) -1}.
+Warn for implicit conversions that may alter a value. This includes
+conversions caused by function prototypes like @code{abs(x)} when
+@code{x} is real and by assignments like
+@code{unsigned x = -1}. Do not warn about explicit casts like
+@code{abs((int)x)} and @code{x = (unsigned) -1}, or if the value is not
+changed by the conversion like @code{abs(2.0)}.
 
 
 @item -Wsign-compare
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-assignments.c 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-assignments.c
--- 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-assignments.c	1970-01-01 01:00:00.000000000 +0100
+++ 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-assignments.c	2006-08-05 18:06:01.000000000 +0100
@@ -0,0 +1,87 @@
+/* Test for diagnostics for Wcoercion in assignments.
+   Origin: Manuel Lopez-Ibanez <lopezibanez@gmail.com> */
+
+/* { dg-do compile }
+/* { dg-options "-fsigned-char -std=c99 -Wcoercion" } */
+
+#include <limits.h>
+#include <float.h>
+
+# define M_PI		3.14159265358979323846	/* pi */
+
+float  vfloat;
+double vdouble;
+long double vlongdouble;
+
+char   vchar;
+short int vshortint;
+int vint;
+long vlongint;
+long long vlonglong;
+
+void h(void)
+{
+  unsigned int ui = 3;
+  int   si = 3;
+  float  f = 3;
+  double d = 3;
+
+  vint = 3.1f; /* { dg-warning "coercion" } */
+  vint = 3.1; /* { dg-warning "coercion" } */
+  vfloat = INT_MAX; /* { dg-warning "coercion" } */
+  vfloat = DBL_MIN; /* { dg-warning "coercion" } */
+  vfloat = M_PI; /* { dg-warning "coercion" } */
+  vfloat = 3.1; /* { dg-warning "coercion" } */
+  vint = d; /* { dg-warning "coercion" } */
+  vfloat = d; /* { dg-warning "coercion" } */
+  vfloat = si; /* { dg-warning "coercion" } */
+  vfloat = ui; /* { dg-warning "coercion" } */
+  vfloat = 16777217; /* { dg-warning "coercion" } */
+
+  /* No warning */
+  vint = 3;
+  vint = 3.0f;
+  vint = 3.0;
+  vint = 16777217.0f;
+  vfloat = 3U;
+  vfloat = 3;
+  vfloat = INT_MIN;
+  vdouble = UINT_MAX;
+  vdouble = ui;
+  vfloat = 3.0;
+  vfloat = 3.1f;
+  vfloat = 0.25;
+  vfloat = f;
+  vdouble = d;
+  vdouble = f;
+  vdouble = 16777217;
+
+}
+
+
+unsigned char vuc;
+unsigned int vui;
+
+void h2(void)
+{
+  unsigned int ui = 3;
+  int   si = 3;
+  unsigned char uc = 3;
+  signed char   sc = 3;
+
+  vint = ui;/* { dg-warning "coercion" } */
+  vui = si; /* { dg-warning "coercion" } */
+  vui = sc; /* { dg-warning "coercion" } */
+  vui = -1; /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+  vui = '\xa0'; /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+  vuc = '\xa0'; /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+
+  /* no warning */
+  vint = uc;
+  vui = uc;
+  vui = 'A';
+  vuc = 'A';
+  vint = 'A';
+  vchar = 'A';
+  vchar = '\xa0';
+}
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-calls.c 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-calls.c
--- 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-calls.c	1970-01-01 01:00:00.000000000 +0100
+++ 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-calls.c	2006-08-05 18:06:01.000000000 +0100
@@ -0,0 +1,87 @@
+/* Test for diagnostics for Wcoercion when passing arguments.
+   Origin: Manuel Lopez-Ibanez <lopezibanez@gmail.com> */
+
+/* { dg-do compile }
+/* { dg-options "-fsigned-char -std=c99 -Wcoercion" } */
+
+#include <limits.h>
+#include <float.h>
+
+# define M_PI		3.14159265358979323846	/* pi */
+
+void fchar(char x);
+void ffloat(float x);
+void fdouble(double x);
+void flongdouble(long double x);
+
+void fshortint(short int x);
+void fint(int x);
+void flongint(long int x);
+void flonglong(long long x);
+
+void h(void)
+{
+  unsigned int ui = 3;
+  int   si = 3;
+  float  f = 3;
+  double d = 3;
+
+  fint(3.1f); /* { dg-warning "coercion" } */
+  fint(3.1); /* { dg-warning "coercion" } */
+  ffloat(INT_MAX); /* { dg-warning "coercion" } */
+  ffloat(DBL_MIN); /* { dg-warning "coercion" } */
+  ffloat(M_PI); /* { dg-warning "coercion" } */
+  ffloat(3.1); /* { dg-warning "coercion" } */
+  fint(d); /* { dg-warning "coercion" } */
+  ffloat(d); /* { dg-warning "coercion" } */
+  ffloat(si); /* { dg-warning "coercion" } */
+  ffloat(ui); /* { dg-warning "coercion" } */
+  ffloat(16777217); /* { dg-warning "coercion" } */
+
+
+  fint(3);
+  fint(3.0f);
+  fint(3.0);
+  fint(16777217.0f);
+  ffloat(3U);
+  ffloat(3);
+  ffloat(INT_MIN);
+  fdouble(UINT_MAX);
+  fdouble(ui);
+  ffloat(3.0);
+  ffloat(3.1f);
+  ffloat(0.25);
+  ffloat(f);
+  fdouble(d);
+  fdouble(f);
+  fdouble(16777217);
+
+}
+
+
+void fuc(unsigned char uc);
+void fui(unsigned int  ui);
+
+void h2(void)
+{
+  unsigned int ui = 3;
+  int   si = 3;
+  unsigned char uc = 3;
+  signed char   sc = 3;
+
+  fint(ui); /* { dg-warning "coercion" } */
+  fui(si);/* { dg-warning "coercion" } */
+  fui(sc); /* { dg-warning "coercion" } */
+  fui(-1); /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+  fui('\xa0'); /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+  fuc('\xa0'); /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+
+
+  fint(uc);
+  fui(uc);
+  fui('A');
+  fuc('A');
+  fint('A');
+  fchar('A');
+  fchar('\xa0');
+}
diff -paur --unidirectional-new-file --exclude='*svn*' --exclude='#*' --exclude='*~' 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-negative-constants.c 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-negative-constants.c
--- 2of3-real_isinteger/gcc/testsuite/gcc.dg/Wcoercion-negative-constants.c	2006-08-06 16:25:08.000000000 +0100
+++ 3of3-coercion_warning/gcc/testsuite/gcc.dg/Wcoercion-negative-constants.c	2006-08-06 16:36:45.000000000 +0100
@@ -15,21 +15,22 @@ void hc (int x)
 
   fuc (-1); /* { dg-warning "negative integer implicitly converted to unsigned type" } */
   uc = -1; /* { dg-warning "negative integer implicitly converted to unsigned type" } */
-  uc = x ? 1U : -1;
+  uc = x ? 1U : -1; /* { dg-warning "coercion to 'unsigned char' from 'unsigned int' may alter its value" } */
   /* { dg-warning "negative integer implicitly converted to unsigned type" "" { target *-*-* } 18 } */
-  uc = x ? SCHAR_MIN : 1U;
+  uc = x ? SCHAR_MIN : 1U; /* { dg-warning "coercion to 'unsigned char' from 'unsigned int' may alter its value" } */
   /* { dg-warning "negative integer implicitly converted to unsigned type" "" { target *-*-* } 20 } */
   uc = '\xa0'; /* { dg-warning "negative integer implicitly converted to unsigned type" } */
 
   fuc('A');
   uc = 'A';
 
-  uc = x ? 1 : -1;
+  uc = x ? 1 : -1; /* { dg-warning "coercion to 'unsigned char' from 'int' may alter its value" } */
 
-  uc = x ? SCHAR_MIN : 1;
+  uc = x ? SCHAR_MIN : 1; /* { dg-warning "coercion to 'unsigned char' from 'int' may alter its value" } */
 }
 
 unsigned fui (unsigned int ui);
+unsigned fsi (signed int ui);
 
 void hi (int x)
 {
@@ -46,12 +47,21 @@ void hi (int x)
   ui = -1 * (1 * -1);
   ui = (unsigned) -1;
 
-  ui = x ? 1 : -1;
+  ui = x ? 1 : -1; /* { dg-warning "coercion to 'unsigned int' from 'int' may alter its value" } */
 
-  ui = x ? INT_MIN : 1;
+  ui = x ? INT_MIN : 1; /* { dg-warning "coercion to 'unsigned int' from 'int' may alter its value" } */
 
-  ui = ui ? SCHAR_MIN : 1;
+  ui = ui ? SCHAR_MIN : 1; /* { dg-warning "coercion to 'unsigned int' from 'int' may alter its value" } */
 }
 
+void hs(void)
+{
+  fsi(UINT_MAX - 1); /* { dg-warning "coercion as 'int' alters 'unsigned int' constant value" } */
+  fsi(UINT_MAX - 1U); /* { dg-warning "coercion as 'int' alters 'unsigned int' constant value" } */
+
+  fsi(UINT_MAX/3U);
+  fsi(UINT_MAX/3);
+  fui(UINT_MAX - 1);
+}
 
 unsigned fui(unsigned a) { return a + -1; } /* { dg-warning "negative integer implicitly converted to unsigned type" } */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]