Hi,

On Fri, Aug 31 2018, Joseph Myers wrote:
> On Fri, 31 Aug 2018, Martin Jambor wrote:
>
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index ebc3ef43ce2..2950760fb2a 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -815,6 +815,10 @@ Wvector-operation-performance
>>  Common Var(warn_vector_operation_performance) Warning
>>  Warn when a vector operation is compiled outside the SIMD.
>>  
>> +Wabsolute-value
>> +Common Var(warn_absolute_value) Warning EnabledBy(Wextra)
>> +Warn on suspicious calls of standard functions computing absolute values.
>
> If it's C-specific I'd expect it to be in c.opt (in the appropriate 
> alphabetical position) and have "C ObjC" instead of Common.

I see, fixed.

>
>> +@item -Wabsolute-value
>> +@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 is specific to C language and can be suppressed with an
>> +explicit type cast.  This warning is also enabled by @option{-Wextra}.
>
> And then the @item would have @r{(C and Objective-C only)}, similar to 
> other such options (rather than saying "specific to C language" in the 
> text).
>

Likewise.

I have bootstrapped and tested the updated (and re-based) patch on
x86-64-linux.  OK for trunk now?

Thank you very much,

Martin


2018-09-03  Martin Jambor  <mjam...@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.
---
 gcc/c-family/c.opt                    |   4 +
 gcc/c/c-parser.c                      | 156 +++++++++++++++++++++++++-
 gcc/doc/invoke.texi                   |   8 ++
 gcc/testsuite/gcc.dg/dfp/warn-abs-2.c |  28 +++++
 gcc/testsuite/gcc.dg/warn-abs-1.c     |  67 +++++++++++
 5 files changed, 257 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/dfp/warn-abs-2.c
 create mode 100644 gcc/testsuite/gcc.dg/warn-abs-1.c

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 31a2b972919..092ec940d86 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -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.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 69ed5ae9d2f..1766a256633 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -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 ();
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f911ae0d1af..953a26ed226 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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)}
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
index 00000000000..c1a1994997f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/warn-abs-2.c
@@ -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
index 00000000000..6aa937c3a2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/warn-abs-1.c
@@ -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);
+}
+
+
+
+
-- 
2.18.0

Reply via email to