Hi,

thank you very much for your comments.

On Fri, Aug 24 2018, Joseph Myers wrote:
> On Fri, 24 Aug 2018, Martin Jambor wrote:
>
>> +/* Assuming we have encountered a call to a probably wrong kind of abs, 
>> issue a
>> +   warning.  LOC is the location of the call, FNKIND is a string 
>> characterizing
>> +   the class of the used abs function, FNDEC is the actual function 
>> declaration
>> +   and ATYPE is type of the supplied actual argument.  */
>
> For proper i18n, you have to use an enumeration here, not English string 
> fragments.
>
>> +  warning_at (loc, OPT_Wabsolute_value,
>> +          "using %s absolute value function %qD when argument "
>> +          "is of %s type %qT", fnkind, fndecl, act, atype);
>
> And then have all the possible combinations as complete sentences, in 
> separate warning_at calls in appropriate switch statments or marked up 
> with G_() if you put more than one in a single warning_at call using ?:, 
> for translation purposes.  (Any cases that are impossible combinations for 
> the warning - you don't want translators to have to produce useless 
> translations where e.g. both argument and call are of the same kind and so 
> the warning shouldn't occur - should use gcc_unreachable ().)

Understood.  That however defeats the purpose of having the warning
string generation in a separate function and so I removed it and just
put separate warning_at calls with the entire string in warn_for_abs.

>
>> +    case BUILT_IN_FABS:
>> +    case BUILT_IN_FABSF:
>> +    case BUILT_IN_FABSL:
>> +      if (!SCALAR_FLOAT_TYPE_P (atype)
>> +      || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype)))
>
> Should include the _FloatN / _FloatNx built-in functions here (CASE_FLT_FN 
> together with CASE_FLT_FN_FLOATN_NX).

OK, fixed.

>
>> +    case BUILT_IN_CABS:
>> +    case BUILT_IN_CABSF:
>> +    case BUILT_IN_CABSL:
>
> And use CASE_FLT_FN here rather than hardcoding the list (but we don't yet 
> have _FloatN / _FloatNx built-in variants of cabs).

Likewise.

>
>> +  tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
>> +  if (tree_fits_uhwi_p (TYPE_SIZE (atype))
>> +      && tree_to_uhwi (TYPE_SIZE (atype)) > tree_to_uhwi (TYPE_SIZE 
>> (ftype)))
>> +    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);
>
> Should not have space at end of warning text.  I don't think TYPE_SIZE is 
> the right thing to use in general; for example, on x86_64, you should warn 
> for passing a _Float128 value to fabsl, but both long double and _Float128 
> are 16-byte types (with only 10 bytes non-padding in long double).

I have looked at how unsafe_conversion_p detects these cases and it
seems it relies entirely on TYPE_PRECISION, so I changed my code to do
the same.  I have also added a test for long double vs _Float128 to the
first test case.

Bootstrapped and tested on x86_64-linux.  What do you think about it
now?

Thanks,

Martin



2018-08-29  Martin Jambor  <mjam...@suse.cz>

        gcc/
        * common.opt (Wabsolute-value): New.
        * doc/invoke.texi (Warning Options): Likewise.

        gcc/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/c-parser.c                      | 155 +++++++++++++++++++++++++-
 gcc/common.opt                        |   4 +
 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, 256 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/c-parser.c b/gcc/c/c-parser.c
index 0d5dbea8f67..c180d9a391e 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -9110,6 +9110,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.
 
@@ -9175,13 +9313,18 @@ c_parser_postfix_expression_after_primary (c_parser 
*parser,
                                              sizeof_arg,
                                              sizeof_ptr_memacc_comptypes);
          if (TREE_CODE (expr.value) == FUNCTION_DECL
-             && DECL_BUILT_IN_CLASS (expr.value) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (expr.value) == BUILT_IN_MEMSET
-             && vec_safe_length (exprlist) == 3)
+             && DECL_BUILT_IN_CLASS (expr.value) == BUILT_IN_NORMAL)
            {
-             tree arg0 = (*exprlist)[0];
-             tree arg2 = (*exprlist)[2];
-             warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask);
+             if (DECL_FUNCTION_CODE (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);
+               }
+             else if (warn_absolute_value
+                      && vec_safe_length (exprlist) == 1)
+               warn_for_abs (expr_loc, expr.value, (*exprlist)[0]);
            }
 
          start = expr.get_start ();
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.
+
 Xassembler
 Driver Separate
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 985ef9f3510..5720841168c 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
+@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}.
+
 @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