Add -Wabsolute-value
authorMartin Jambor <mjambor@suse.cz>
Mon, 17 Sep 2018 13:12:12 +0000 (15:12 +0200)
committerMartin Jambor <jamborm@gcc.gnu.org>
Mon, 17 Sep 2018 13:12:12 +0000 (15:12 +0200)
2018-09-17  Martin Jambor  <mjambor@suse.cz>

gcc/
* doc/invoke.texi (Warning Options): Likewise.

gcc/c-family/
* c.opt (Wabsolute-value): New.

gcc/c/
* c-parser.c: (warn_for_abs): New function.
(c_parser_postfix_expression_after_primary): Call it.

testsuite/
* gcc.dg/warn-abs-1.c: New test.
* gcc.dg/dfp/warn-abs-2.c: Likewise.

From-SVN: r264368

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/dfp/warn-abs-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/warn-abs-1.c [new file with mode: 0644]

index 738f0c3fbb5a0f3548c12ac1504b2b8a66bf8268..f653d66f28849b652dd91bff682f4f225d34668b 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-17  Martin Jambor  <mjambor@suse.cz>
+
+       PR c/63886
+       * doc/invoke.texi (Warning Options): Likewise.
+
 2018-09-17  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/87301
index 75064a2b684d57fbe0f4cd177557f9882b6d4148..b299ad2bc22b82439952fa6c6087397646a0a922 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-17  Martin Jambor  <mjambor@suse.cz>
+
+       PR c/63886
+       * c.opt (Wabsolute-value): New.
+
 2018-09-06  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * c-common.c (complete_flexible_array_elts): New helper function.
index 31a2b972919eb7e96899fc88e695f59444968875..092ec940d860b35f895e07b96b3662c3cbe9ab7d 100644 (file)
@@ -271,6 +271,10 @@ Warn if a subobject has an abi_tag attribute that the complete object type does
 Wpsabi
 C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Warning Undocumented LangEnabledBy(C ObjC C++ ObjC++,Wabi)
 
+Wabsolute-value
+C ObjC Var(warn_absolute_value) Warning EnabledBy(Wextra)
+Warn on suspicious calls of standard functions computing absolute values.
+
 Waddress
 C ObjC C++ ObjC++ Var(warn_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn about suspicious uses of memory addresses.
index c28fb1c0ebc7232345d2413baf36ca0f61ddff4b..3133ca6b6b074384f27c0deb1a356d0097c80b8f 100644 (file)
@@ -1,3 +1,9 @@
+2018-09-17  Martin Jambor  <mjambor@suse.cz>
+
+       PR c/63886
+       * c-parser.c: (warn_for_abs): New function.
+       (c_parser_postfix_expression_after_primary): Call it.
+
 2018-09-13  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * c-typeck.c (digest_init): Shorten overlength strings.
index 69ed5ae9d2fffd3323b1022dd2aa5bca54714b39..1766a256633bc41a67e0f42fc1c62ac5fe564eef 100644 (file)
@@ -9101,6 +9101,144 @@ sizeof_ptr_memacc_comptypes (tree type1, tree type2)
   return comptypes (type1, type2) == 1;
 }
 
+/* Warn for patterns where abs-like function appears to be used incorrectly,
+   gracely ignore any non-abs-like function.  The warning location should be
+   LOC.  FNDECL is the declaration of called function, it must be a
+   BUILT_IN_NORMAL function.  ARG is the first and only argument of the
+   call.  */
+
+static void
+warn_for_abs (location_t loc, tree fndecl, tree arg)
+{
+  tree atype = TREE_TYPE (arg);
+
+  /* Casts from pointers (and thus arrays and fndecls) will generate
+     -Wint-conversion warnings.  Most other wrong types hopefully lead to type
+     mismatch errors.  TODO: Think about what to do with FIXED_POINT_TYPE_P
+     types and possibly other exotic types.  */
+  if (!INTEGRAL_TYPE_P (atype)
+      && !SCALAR_FLOAT_TYPE_P (atype)
+      && TREE_CODE (atype) != COMPLEX_TYPE)
+    return;
+
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+  switch (fcode)
+    {
+    case BUILT_IN_ABS:
+    case BUILT_IN_LABS:
+    case BUILT_IN_LLABS:
+    case BUILT_IN_IMAXABS:
+      if (!INTEGRAL_TYPE_P (atype))
+       {
+         if (SCALAR_FLOAT_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using integer absolute value function %qD when "
+                       "argument is of floating point type %qT",
+                       fndecl, atype);
+         else if (TREE_CODE (atype) == COMPLEX_TYPE)
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using integer absolute value function %qD when "
+                       "argument is of complex type %qT", fndecl, atype);
+         else
+           gcc_unreachable ();
+         return;
+       }
+      if (TYPE_UNSIGNED (atype))
+       warning_at (loc, OPT_Wabsolute_value,
+                   "taking the absolute value of unsigned type %qT "
+                   "has no effect", atype);
+      break;
+
+    CASE_FLT_FN (BUILT_IN_FABS):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
+      if (!SCALAR_FLOAT_TYPE_P (atype)
+         || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype)))
+       {
+         if (INTEGRAL_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using floating point absolute value function %qD "
+                       "when argument is of integer type %qT", fndecl, atype);
+         else if (DECIMAL_FLOAT_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using floating point absolute value function %qD "
+                       "when argument is of decimal floating point type %qT",
+                       fndecl, atype);
+         else if (TREE_CODE (atype) == COMPLEX_TYPE)
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using floating point absolute value function %qD when "
+                       "argument is of complex type %qT", fndecl, atype);
+         else
+           gcc_unreachable ();
+         return;
+       }
+      break;
+
+    CASE_FLT_FN (BUILT_IN_CABS):
+      if (TREE_CODE (atype) != COMPLEX_TYPE)
+       {
+         if (INTEGRAL_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using complex absolute value function %qD when "
+                       "argument is of integer type %qT", fndecl, atype);
+         else if (SCALAR_FLOAT_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using complex absolute value function %qD when "
+                       "argument is of floating point type %qT",
+                       fndecl, atype);
+         else
+           gcc_unreachable ();
+
+         return;
+       }
+      break;
+
+    case BUILT_IN_FABSD32:
+    case BUILT_IN_FABSD64:
+    case BUILT_IN_FABSD128:
+      if (!DECIMAL_FLOAT_TYPE_P (atype))
+       {
+         if (INTEGRAL_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using decimal floating point absolute value "
+                       "function %qD when argument is of integer type %qT",
+                       fndecl, atype);
+         else if (SCALAR_FLOAT_TYPE_P (atype))
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using decimal floating point absolute value "
+                       "function %qD when argument is of floating point "
+                       "type %qT", fndecl, atype);
+         else if (TREE_CODE (atype) == COMPLEX_TYPE)
+           warning_at (loc, OPT_Wabsolute_value,
+                       "using decimal floating point absolute value "
+                       "function %qD when argument is of complex type %qT",
+                       fndecl, atype);
+         else
+           gcc_unreachable ();
+         return;
+       }
+      break;
+
+    default:
+      return;
+    }
+
+  tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+  if (TREE_CODE (atype) == COMPLEX_TYPE)
+    {
+      gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE);
+      atype = TREE_TYPE (atype);
+      ftype = TREE_TYPE (ftype);
+    }
+
+  if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype))
+    warning_at (loc, OPT_Wabsolute_value,
+               "absolute value function %qD given an argument of type %qT "
+               "but has parameter of type %qT which may cause truncation "
+               "of value", fndecl, atype, ftype);
+}
+
+
 /* Parse a postfix expression after the initial primary or compound
    literal; that is, parse a series of postfix operators.
 
@@ -9165,13 +9303,19 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
                                              expr.value, exprlist,
                                              sizeof_arg,
                                              sizeof_ptr_memacc_comptypes);
-         if (TREE_CODE (expr.value) == FUNCTION_DECL
-             && fndecl_built_in_p (expr.value, BUILT_IN_MEMSET)
-             && vec_safe_length (exprlist) == 3)
+         if (TREE_CODE (expr.value) == FUNCTION_DECL)
            {
-             tree arg0 = (*exprlist)[0];
-             tree arg2 = (*exprlist)[2];
-             warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask);
+             if (fndecl_built_in_p (expr.value, BUILT_IN_MEMSET)
+                 && vec_safe_length (exprlist) == 3)
+               {
+                 tree arg0 = (*exprlist)[0];
+                 tree arg2 = (*exprlist)[2];
+                 warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask);
+               }
+             if (warn_absolute_value
+                 && fndecl_built_in_p (expr.value, BUILT_IN_NORMAL)
+                 && vec_safe_length (exprlist) == 1)
+               warn_for_abs (expr_loc, expr.value, (*exprlist)[0]);
            }
 
          start = expr.get_start ();
index ec127113356b8c2bc88d15c5f787b53ae03f2ab8..94304c314cfb74a50ffd9a32b7b7cfc417144954 100644 (file)
@@ -6281,6 +6281,14 @@ example, warn if an unsigned variable is compared against zero with
 @code{<} or @code{>=}.  This warning is also enabled by
 @option{-Wextra}.
 
+@item -Wabsolute-value @r{(C and Objective-C only)}
+@opindex Wabsolute-value
+@opindex Wno-absolute-value
+Warn when a wrong absolute value function seems to be used or when it
+does not have any effect because its argument is an unsigned type.
+This warning be suppressed with an explicit type cast and it is also
+enabled by @option{-Wextra}.
+
 @include cppwarnopts.texi
 
 @item -Wbad-function-cast @r{(C and Objective-C only)}
index 2e7c87875111df87130bfbea45e8f2c5c76523e0..4fd1ff928ab660f1985dcee6e969df56019a9be5 100644 (file)
@@ -1,3 +1,9 @@
+2018-09-17  Martin Jambor  <mjambor@suse.cz>
+
+       PR c/63886
+       * gcc.dg/warn-abs-1.c: New test.
+       * gcc.dg/dfp/warn-abs-2.c: Likewise.
+
 2018-09-17  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * gcc.target/x86_64/abi/ms-sysv/ms-sysv.exp: Don't pass
diff --git a/gcc/testsuite/gcc.dg/dfp/warn-abs-2.c b/gcc/testsuite/gcc.dg/dfp/warn-abs-2.c
new file mode 100644 (file)
index 0000000..c1a1994
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-Wabsolute-value" } */
+
+#include <stdlib.h>
+#include <complex.h>
+#include <math.h>
+
+void tst_decimal (_Decimal32 *p32, _Decimal64 *p64, _Decimal128 *p128)
+{
+  *p32 = abs(*p32);       /* { dg-warning "using integer absolute value function" } */
+  *p64 = fabs(*p64);      /* { dg-warning "using floating point absolute value function" } */
+  *p128 = cabsl(*p128);   /* { dg-warning "using complex absolute value function" } */
+}
+
+void tst_notdecimal (int *pi, double *pd, long double *pld, complex double *pc)
+{
+  *pi = __builtin_fabsd32 (*pi);   /* { dg-warning "using decimal floating point absolute value function" } */
+  *pd = __builtin_fabsd64 (*pd);   /* { dg-warning "using decimal floating point absolute value function" } */
+  *pld = __builtin_fabsd64 (*pld); /* { dg-warning "using decimal floating point absolute value function" } */
+  *pc = __builtin_fabsd128 (*pc);  /* { dg-warning "using decimal floating point absolute value function" } */
+}
+
+void
+test_size  (_Decimal64 *p64, _Decimal128 *p128)
+{
+  *p64 = __builtin_fabsd32 (*p64);   /* { dg-warning "may cause truncation of value" } */
+  *p128 = __builtin_fabsd64 (*p128); /* { dg-warning "may cause truncation of value" } */
+}
diff --git a/gcc/testsuite/gcc.dg/warn-abs-1.c b/gcc/testsuite/gcc.dg/warn-abs-1.c
new file mode 100644 (file)
index 0000000..6aa937c
--- /dev/null
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Wabsolute-value" } */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <math.h>
+#include <complex.h>
+
+void
+tst_unsigned (unsigned *pu, unsigned long *pl, unsigned long long *pll,
+             uintmax_t *pm)
+{
+  *pu = abs (*pu);      /* { dg-warning "taking the absolute value of unsigned type" } */
+  *pl = labs (*pl);     /* { dg-warning "taking the absolute value of unsigned type" } */
+  *pll = llabs (*pll);  /* { dg-warning "taking the absolute value of unsigned type" } */
+  *pm = imaxabs (*pm);      /* { dg-warning "taking the absolute value of unsigned type" } */
+}
+
+void
+test_int_size (long long *pll)
+{
+  *pll = abs (*pll);  /* { dg-warning "may cause truncation of value" } */
+  *pll = abs ((int) *pll);
+}
+
+void
+tst_notint (float *pf, double *pd, _Complex double *pc)
+{
+  *pf = abs (*pf);    /* { dg-warning "using integer absolute value function" } */
+  *pd = labs (*pd);   /* { dg-warning "using integer absolute value function" } */
+  *pc = abs (*pc);    /* { dg-warning "using integer absolute value function" } */
+}
+
+void
+tst_notfloat (int *pi, long *pl, complex double *pc)
+{
+  *pi = fabsf (*pi);  /* { dg-warning "using floating point absolute value function" } */
+  *pl = fabs (*pl);   /* { dg-warning "using floating point absolute value function" } */
+  *pc = fabs (*pc);   /* { dg-warning "using floating point absolute value function" } */
+}
+
+void
+tst_float_size (double *pd, long double *pld, _Float128 *pf128)
+{
+  *pd = fabsf (*pd);   /* { dg-warning "may cause truncation of value" } */
+  *pld = fabs (*pld);  /* { dg-warning "may cause truncation of value" } */
+  *pld = fabs ((double) *pld);
+  *pf128 = fabsl (*pf128); /* { dg-warning "may cause truncation of value" } */
+}
+
+void tst_notcomplex (int *pi, long *pl, long double *pld)
+{
+  *pi = cabs (*pi);   /* { dg-warning "using complex absolute value function" } */
+  *pl = cabs (*pl);   /* { dg-warning "using complex absolute value function" } */
+  *pld = cabsl (*pld);/* { dg-warning "using complex absolute value function" } */
+}
+
+void tst_cplx_size (complex double *pcd, complex long double *pcld)
+{
+  *pcd = cabsf (*pcd);   /* { dg-warning "may cause truncation of value" } */
+  *pcld = cabs (*pcld);  /* { dg-warning "may cause truncation of value" } */
+  *pcld = cabs ((complex double) *pcld);
+}
+
+
+
+