This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH, PR 53001] Re: Patch to split out new warning flag for floating point conversion
- From: Joshua J Cogliati <jrincayc at yahoo dot com>
- To: "Joseph S. Myers" <joseph at codesourcery dot com>
- Cc: Dodji Seketeli <dodji at redhat dot com>, gcc-patches at gcc dot gnu dot org, jason at redhat dot com, manu at gcc dot gnu dot org
- Date: Tue, 22 Oct 2013 20:58:06 -0600
- Subject: Re: [PATCH, PR 53001] Re: Patch to split out new warning flag for floating point conversion
- Authentication-results: sourceware.org; auth=none
- References: <52554AA2 dot 50706 at yahoo dot com> <Pine dot LNX dot 4 dot 64 dot 1310092037370 dot 12619 at digraph dot polyomino dot org dot uk> <525AA8E5 dot 807 at yahoo dot com> <87zjqcp6jx dot fsf at redhat dot com> <Pine dot LNX dot 4 dot 64 dot 1310142333000 dot 19760 at digraph dot polyomino dot org dot uk> <52613001 dot 9030606 at yahoo dot com> <Pine dot LNX dot 4 dot 64 dot 1310181516380 dot 16441 at digraph dot polyomino dot org dot uk>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Only one of these should be applied. The
warn_float_patch_simple_trunk.diff just changes formatting from the
previous version. The warn_float_patch_and_new_testcase.diff leaves
existing testcases alone, and adds a new one that tests
- -Wfloat-conversion warnings. warn_float_patch_and_new_testcase.diff
has been run thru make bootstrap and make check-gcc on revision 203640
of svn trunk.
Changelog for warn_float_patch_simple_trunk.diff:
Splitting out a -Wfloat-conversion from -Wconversion for
conversions that lower floating point number precision
or conversion from floating point numbers to integers
* c-family/c-common.c Switching unsafe_conversion_p to
return an enumeration with more detail, and conversion_warning
to use this information.
* c-family/c-common.h Adding conversion_safety enumeration
and switching return type of unsafe_conversion_p
* c-family/c.opt Adding new warning float-conversion and
enabling it -Wconversion
* doc/invoke.texi Adding documentation about
-Wfloat-conversion
* testsuite/c-c++-common/Wconversion-real.c Switching tests
to use float-conversion
* testsuite/gcc.dg/Wconversion-real-integer.c Switching
tests to use float-conversion
* testsuite/gcc.dg/pr35635.c Switching tests to use
float-conversion
Changelog for warn_float_patch_and_new_testcase.diff:
Splitting out a -Wfloat-conversion from -Wconversion for
conversions that lower floating point number precision
or conversion from floating point numbers to integers
* c-family/c-common.c Switching unsafe_conversion_p to
return an enumeration with more detail, and conversion_warning
to use this information.
* c-family/c-common.h Adding conversion_safety enumeration
and switching return type of unsafe_conversion_p
* c-family/c.opt Adding new warning float-conversion and
enabling it -Wconversion
* doc/invoke.texi Adding documentation about
-Wfloat-conversion
* 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 ones that are warned about by
-Wfloat-conversion
On 10/18/2013 09:21 AM, Joseph S. Myers wrote:
> On Fri, 18 Oct 2013, Joshua J Cogliati wrote:
>
>> This patch does not change any of the non-commented c and c++
>> code. It changes the dg comments. Example: - fsi (3.1f); /* {
>> dg-warning "conversion" } */ + fsi (3.1f); /* { dg-warning
>> "float-conversion" } */
>>
>> If you want I can change it to (in separate files if desired):
>>
>> fsi (3.1f); /* { dg-warning "conversion" } */ fsi (3.1f); /* {
>> dg-warning "float-conversion" } */
>>
>> so that now the tests are run both ways, but it would test the
>> exact same code path.
>
> Really I think it's better for the dg-warning text to test the
> actual warning text rather than the name of the option that's also
> reported as part of the compiler output ("conversion" matches both,
> of course).
Is there an example of how this works or documentation? I would
rather not make it overly detailed so it becomes very sensitive to
minor changes in the warning format.
> The problem isn't so much the change to dg-warning, though, as the
> change to dg-options. Previously the test asserted that certain
> things warn with -Wconversion, by changing it you lose the
> assertion that -Wconversion enables those warnings. So I think the
> test should remain as-is, verifying that -Wfloat-conversion causes
> certain warnings, and then be copied in a form using
> -Wfloat-conversion to verify that -Wfloat-conversion also causes
> the same warnings.
I am not fully convinced, so I just made the patch both ways. I don't
care that much which is used.
> Looking at
> <http://gcc.gnu.org/ml/gcc-patches/2013-10/msg01148.html>, there
> are also some formatting problems, "if(" which should have a space
> before the "(".
>
Fixed.
Thanks for the comments.
Joshua Cogliati
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.14 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQEcBAEBAgAGBQJSZzs5AAoJEFeOW05LP1faBu0IAKOBXUGOrS8H53x2pN+UXdK7
H6EeypuCmlD3qFC1k2G3GIvaxrUAECxid2gaVABVpc4+0JJ2fYXMH2lwGaAiMlNv
ftdQ3c4oRLHHCKvu1UuZ3I/iwJ7ffQpYWxMhYLTdPkXxyEqoFm7cD3GYP3THGKhr
Sx1rxUGVQC2txRIiesEqrEOeO0XhoqnhneCH5rTpNSpsMghlibyGPG7Ag5aGEUJk
DfA+EacU6oKB9Uz98pCGaRAf7fiLZp5c9ug+aBFEgmZoBrnSE22tbor8SdcbSUyt
6yGkAENiJIhyMrkedT+9QxEBXzFv4/yh1av0W8bERGcLgH1tbLbydyDREL7kEZ4=
=4pyZ
-----END PGP SIGNATURE-----
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c (revision 203640)
+++ gcc/c-family/c-common.c (working copy)
@@ -2518,7 +2518,7 @@ shorten_binary_op (tree result_type, tre
}
/* 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.
@@ -2526,12 +2526,12 @@ shorten_binary_op (tree result_type, tre
* 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);
@@ -2543,7 +2543,7 @@ unsafe_conversion_p (tree type, tree exp
&& 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
@@ -2564,7 +2564,7 @@ unsafe_conversion_p (tree type, tree exp
" constant value to negative integer");
}
else
- give_warning = true;
+ give_warning = UNSAFE_OTHER;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
@@ -2573,7 +2573,7 @@ unsafe_conversion_p (tree type, tree exp
{
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. */
@@ -2582,7 +2582,7 @@ unsafe_conversion_p (tree type, tree exp
{
REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
}
}
@@ -2591,7 +2591,7 @@ unsafe_conversion_p (tree type, tree exp
/* 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)
@@ -2629,7 +2629,7 @@ unsafe_conversion_p (tree type, tree exp
&& 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
@@ -2638,12 +2638,12 @@ unsafe_conversion_p (tree type, tree exp
|| (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. */
@@ -2679,14 +2679,14 @@ unsafe_conversion_p (tree type, tree exp
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;
@@ -2700,8 +2700,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))
@@ -2728,7 +2729,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);
@@ -2747,7 +2753,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: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h (revision 203640)
+++ gcc/c-family/c-common.h (working copy)
@@ -685,6 +685,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;
@@ -738,7 +748,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: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt (revision 203640)
+++ gcc/c-family/c.opt (working copy)
@@ -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: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (revision 203640)
+++ gcc/doc/invoke.texi (working copy)
@@ -263,7 +263,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
@@ -4570,6 +4571,14 @@ value, like assigning a signed integer e
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: gcc/testsuite/c-c++-common/Wfloat-conversion.c
===================================================================
--- gcc/testsuite/c-c++-common/Wfloat-conversion.c (working copy)
+++ gcc/testsuite/c-c++-common/Wfloat-conversion.c (working copy)
@@ -1,85 +1,58 @@
/* Test for diagnostics for Wconversion for floating-point. */
/* { dg-do compile } */
-/* { dg-skip-if "doubles are floats" { "avr-*-*" } { "*" } { "" } } */
-/* { dg-options "-std=c99 -Wconversion" { target c } } */
-/* { dg-options "-Wconversion" { target c++ } } */
+/* { 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" } */
- vfloat = 3.1; /* { dg-warning "conversion" } */
- ffloat (3.1L); /* { dg-warning "conversion" } */
- vfloat = 3.1L; /* { dg-warning "conversion" } */
- fdouble (3.1L); /* { dg-warning "conversion" "" { target large_long_double } } */
- vdouble = 3.1L; /* { dg-warning "conversion" "" { target large_long_double } } */
- ffloat (vdouble); /* { dg-warning "conversion" } */
- vfloat = vdouble; /* { dg-warning "conversion" } */
- ffloat (vlongdouble); /* { dg-warning "conversion" } */
- vfloat = vlongdouble; /* { dg-warning "conversion" } */
- fdouble (vlongdouble); /* { dg-warning "conversion" "" { target large_long_double } } */
- vdouble = vlongdouble; /* { dg-warning "conversion" "" { target large_long_double } } */
-
-
- ffloat ((float) 3.1);
- vfloat = (float) 3.1;
- ffloat ((float) 3.1L);
- vfloat = (float) 3.1L;
- fdouble ((double) 3.1L);
- vdouble = (double) 3.1L;
- ffloat ((float) vdouble);
- vfloat = (float) vdouble;
- ffloat ((float) vlongdouble);
- vfloat = (float) vlongdouble;
- fdouble ((double) vlongdouble);
- vdouble = (double) vlongdouble;
-
-
- ffloat (3.0);
- vfloat = 3.0;
- ffloat (3.1f);
- vfloat = 3.1f;
- ffloat (0.25L);
- vfloat = 0.25L;
-
-
- fdouble (3.0);
- vdouble = 3.0;
- fdouble (3.1f);
- vdouble = 3.1f;
- fdouble (0.25L);
- vdouble = 0.25L;
-
- flongdouble (3.0);
- vlongdouble = 3.0;
- flongdouble (3.1f);
- vlongdouble = 3.1f;
- flongdouble (0.25L);
- vlongdouble = 0.25L;
-
- ffloat (f);
- vfloat = f;
- fdouble (f);
- vdouble = f;
- fdouble (d);
- vdouble = d;
- flongdouble (f);
- vlongdouble = f;
- flongdouble (d);
- vlongdouble = d;
- flongdouble (ld);
- vlongdouble = ld;
+ ffloat (3.1); /* { dg-warning "float-conversion" } */
+ vfloat = 3.1; /* { dg-warning "float-conversion" } */
+ ffloat (3.1L); /* { dg-warning "float-conversion" } */
+ vfloat = 3.1L; /* { dg-warning "float-conversion" } */
+ fdouble (3.1L); /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ vdouble = 3.1L; /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ ffloat (vdouble); /* { dg-warning "float-conversion" } */
+ vfloat = vdouble; /* { dg-warning "float-conversion" } */
+ ffloat (vlongdouble); /* { dg-warning "float-conversion" } */
+ vfloat = vlongdouble; /* { dg-warning "float-conversion" } */
+ fdouble (vlongdouble); /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ vdouble = vlongdouble; /* { dg-warning "float-conversion" "" { target large_long_double } } */
+
+ fsi (3.1f); /* { dg-warning "float-conversion" } */
+ si = 3.1f; /* { dg-warning "float-conversion" } */
+ fsi (3.1); /* { dg-warning "float-conversion" } */
+ si = 3.1; /* { dg-warning "float-conversion" } */
+ fsi (d); /* { dg-warning "float-conversion" } */
+ si = d; /* { dg-warning "float-conversion" } */
+ ffloat (INT_MAX); /* { dg-warning "float-conversion" } */
+ vfloat = INT_MAX; /* { dg-warning "float-conversion" } */
+ ffloat (16777217); /* { dg-warning "float-conversion" } */
+ vfloat = 16777217; /* { dg-warning "float-conversion" } */
+
+ sc = bar != 0 ? 2.1 : 10; /* { dg-warning "float-conversion" } */
+ uc = bar != 0 ? 2.1 : 10; /* { dg-warning "float-conversion" } */
}
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c (revision 203640)
+++ gcc/c-family/c-common.c (working copy)
@@ -2518,7 +2518,7 @@ shorten_binary_op (tree result_type, tre
}
/* 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.
@@ -2526,12 +2526,12 @@ shorten_binary_op (tree result_type, tre
* 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);
@@ -2543,7 +2543,7 @@ unsafe_conversion_p (tree type, tree exp
&& 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
@@ -2564,7 +2564,7 @@ unsafe_conversion_p (tree type, tree exp
" constant value to negative integer");
}
else
- give_warning = true;
+ give_warning = UNSAFE_OTHER;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
@@ -2573,7 +2573,7 @@ unsafe_conversion_p (tree type, tree exp
{
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. */
@@ -2582,7 +2582,7 @@ unsafe_conversion_p (tree type, tree exp
{
REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a))
- give_warning = true;
+ give_warning = UNSAFE_REAL;
}
}
}
@@ -2591,7 +2591,7 @@ unsafe_conversion_p (tree type, tree exp
/* 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)
@@ -2629,7 +2629,7 @@ unsafe_conversion_p (tree type, tree exp
&& 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
@@ -2638,12 +2638,12 @@ unsafe_conversion_p (tree type, tree exp
|| (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. */
@@ -2679,14 +2679,14 @@ unsafe_conversion_p (tree type, tree exp
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;
@@ -2700,8 +2700,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))
@@ -2728,7 +2729,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);
@@ -2747,7 +2753,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: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h (revision 203640)
+++ gcc/c-family/c-common.h (working copy)
@@ -685,6 +685,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;
@@ -738,7 +748,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: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt (revision 203640)
+++ gcc/c-family/c.opt (working copy)
@@ -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: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (revision 203640)
+++ gcc/doc/invoke.texi (working copy)
@@ -263,7 +263,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
@@ -4570,6 +4571,14 @@ value, like assigning a signed integer e
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: gcc/testsuite/c-c++-common/Wconversion-real.c
===================================================================
--- gcc/testsuite/c-c++-common/Wconversion-real.c (revision 203640)
+++ gcc/testsuite/c-c++-common/Wconversion-real.c (working copy)
@@ -2,8 +2,8 @@
/* { dg-do compile } */
/* { dg-skip-if "doubles are floats" { "avr-*-*" } { "*" } { "" } } */
-/* { dg-options "-std=c99 -Wconversion" { target c } } */
-/* { dg-options "-Wconversion" { target c++ } } */
+/* { dg-options "-std=c99 -Wfloat-conversion" { target c } } */
+/* { dg-options "-Wfloat-conversion" { target c++ } } */
/* { dg-require-effective-target large_double } */
float vfloat;
@@ -20,18 +20,18 @@ void h (void)
double d = 0;
long double ld = 0;
- ffloat (3.1); /* { dg-warning "conversion" } */
- vfloat = 3.1; /* { dg-warning "conversion" } */
- ffloat (3.1L); /* { dg-warning "conversion" } */
- vfloat = 3.1L; /* { dg-warning "conversion" } */
- fdouble (3.1L); /* { dg-warning "conversion" "" { target large_long_double } } */
- vdouble = 3.1L; /* { dg-warning "conversion" "" { target large_long_double } } */
- ffloat (vdouble); /* { dg-warning "conversion" } */
- vfloat = vdouble; /* { dg-warning "conversion" } */
- ffloat (vlongdouble); /* { dg-warning "conversion" } */
- vfloat = vlongdouble; /* { dg-warning "conversion" } */
- fdouble (vlongdouble); /* { dg-warning "conversion" "" { target large_long_double } } */
- vdouble = vlongdouble; /* { dg-warning "conversion" "" { target large_long_double } } */
+ ffloat (3.1); /* { dg-warning "float-conversion" } */
+ vfloat = 3.1; /* { dg-warning "float-conversion" } */
+ ffloat (3.1L); /* { dg-warning "float-conversion" } */
+ vfloat = 3.1L; /* { dg-warning "float-conversion" } */
+ fdouble (3.1L); /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ vdouble = 3.1L; /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ ffloat (vdouble); /* { dg-warning "float-conversion" } */
+ vfloat = vdouble; /* { dg-warning "float-conversion" } */
+ ffloat (vlongdouble); /* { dg-warning "float-conversion" } */
+ vfloat = vlongdouble; /* { dg-warning "float-conversion" } */
+ fdouble (vlongdouble); /* { dg-warning "float-conversion" "" { target large_long_double } } */
+ vdouble = vlongdouble; /* { dg-warning "float-conversion" "" { target large_long_double } } */
ffloat ((float) 3.1);
Index: gcc/testsuite/gcc.dg/Wconversion-real-integer.c
===================================================================
--- gcc/testsuite/gcc.dg/Wconversion-real-integer.c (revision 203640)
+++ gcc/testsuite/gcc.dg/Wconversion-real-integer.c (working copy)
@@ -25,18 +25,18 @@ void h (void)
float f = 3;
double d = 3;
- fsi (3.1f); /* { dg-warning "conversion" } */
- si = 3.1f; /* { dg-warning "conversion" } */
- fsi (3.1); /* { dg-warning "conversion" } */
- si = 3.1; /* { dg-warning "conversion" } */
- fsi (d); /* { dg-warning "conversion" } */
- si = d; /* { dg-warning "conversion" } */
+ fsi (3.1f); /* { dg-warning "float-conversion" } */
+ si = 3.1f; /* { dg-warning "float-conversion" } */
+ fsi (3.1); /* { dg-warning "float-conversion" } */
+ si = 3.1; /* { dg-warning "float-conversion" } */
+ fsi (d); /* { dg-warning "float-conversion" } */
+ si = d; /* { dg-warning "float-conversion" } */
fui (-1.0); /* { dg-warning "overflow" } */
ui = -1.0; /* { dg-warning "overflow" } */
- ffloat (INT_MAX); /* { dg-warning "conversion" } */
- vfloat = INT_MAX; /* { dg-warning "conversion" } */
- ffloat (16777217); /* { dg-warning "conversion" } */
- vfloat = 16777217; /* { dg-warning "conversion" } */
+ ffloat (INT_MAX); /* { dg-warning "float-conversion" } */
+ vfloat = INT_MAX; /* { dg-warning "float-conversion" } */
+ ffloat (16777217); /* { dg-warning "float-conversion" } */
+ vfloat = 16777217; /* { dg-warning "float-conversion" } */
ffloat (si); /* { dg-warning "conversion" } */
vfloat = si; /* { dg-warning "conversion" } */
ffloat (ui); /* { dg-warning "conversion" } */
Index: gcc/testsuite/gcc.dg/pr35635.c
===================================================================
--- gcc/testsuite/gcc.dg/pr35635.c (revision 203640)
+++ gcc/testsuite/gcc.dg/pr35635.c (working copy)
@@ -45,7 +45,7 @@ void func2()
/* At least one branch of ? does not fit in the destination, thus
warn. */
- schar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion" } */
+ schar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "float-conversion" } */
schar_x = bar != 0 ? (signed char) 1024: -1024; /* { dg-warning "conversion" } */
}
@@ -61,7 +61,7 @@ void func3()
/* At least one branch of ? does not fit in the destination, thus
warn. */
- uchar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion" } */
+ uchar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "float-conversion" } */
uchar_x = bar != 0
? (unsigned char) 1024
: -1; /* { dg-warning "negative integer implicitly converted to unsigned type" } */