-----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" } */