Commit 49b0aa18 by Joshua J Cogliati Committed by Manuel López-Ibáñez

re PR c/53001 (-Wfloat-conversion should be available to warn about floating point errors)

2013-11-19  Joshua J Cogliati  <jrincayc@yahoo.com>

	PR c/53001
	Splitting out a -Wfloat-conversion from -Wconversion for
	conversions that lower floating point number precision
	or conversion from floating point numbers to integers.

gcc/c-family/

	* c-common.c (unsafe_conversion_p): Make this function
	return an enumeration with more detail.
	(conversion_warning): Use the new return type of
	unsafe_conversion_p to separately warn either about conversions
	that lower floating point number precision or about the other
	kinds of conversions.
 	* c-common.h (enum conversion_safety): New enumeration.
 	(unsafe_conversion_p): switching return type to
 	conversion_safety enumeration.
	* c.opt: Adding new warning -Wfloat-conversion and
	enabling it with -Wconversion.

gcc/

	* doc/invoke.texi: Adding documentation about
	-Wfloat-conversion.

gcc/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 conversions that are warned about by
	-Wfloat-conversion.

From-SVN: r205090
parent 3b891d26
2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com>
PR c/53001
* doc/invoke.texi: Adding documentation about
-Wfloat-conversion.
2013-11-20 Miro Kropacek <miro.kropacek@gmail.com> 2013-11-20 Miro Kropacek <miro.kropacek@gmail.com>
* config/m68k/m68k.c (m68k_option_overrides): Fix typo. * config/m68k/m68k.c (m68k_option_overrides): Fix typo.
2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com>
PR c/53001
* c-common.c (unsafe_conversion_p): Make this function
return an enumeration with more detail.
(conversion_warning): Use the new return type of
unsafe_conversion_p to separately warn either about conversions
that lower floating point number precision or about the other
kinds of conversions.
* c-common.h (enum conversion_safety): New enumeration.
(unsafe_conversion_p): switching return type to
conversion_safety enumeration.
* c.opt: Adding new warning -Wfloat-conversion and
enabling it with -Wconversion.
2013-11-19 Basile Starynkevitch <basile@starynkevitch.net> 2013-11-19 Basile Starynkevitch <basile@starynkevitch.net>
* c-opts.c: Include plugin.h. * c-opts.c: Include plugin.h.
......
...@@ -2537,7 +2537,7 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) ...@@ -2537,7 +2537,7 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
} }
/* Checks if expression EXPR of real/integer type cannot be converted /* 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 a constant which cannot be exactly converted to TYPE
* EXPR is not a constant and size of EXPR's type > than size of 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. for EXPR type and TYPE being both integers or both real.
...@@ -2545,12 +2545,12 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) ...@@ -2545,12 +2545,12 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
* EXPR is not a constant of integer type which cannot be * EXPR is not a constant of integer type which cannot be
exactly converted to real type. exactly converted to real type.
Function allows conversions between types of different signedness and Function allows conversions between types of different signedness and
does not return true in that case. Function can produce signedness can return SAFE_CONVERSION (zero) in that case. Function can produce
warnings if PRODUCE_WARNS is true. */ signedness warnings if PRODUCE_WARNS is true. */
bool enum conversion_safety
unsafe_conversion_p (tree type, tree expr, bool produce_warns) 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); tree expr_type = TREE_TYPE (expr);
location_t loc = EXPR_LOC_OR_HERE (expr); location_t loc = EXPR_LOC_OR_HERE (expr);
...@@ -2562,7 +2562,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2562,7 +2562,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
&& TREE_CODE (type) == INTEGER_TYPE) && TREE_CODE (type) == INTEGER_TYPE)
{ {
if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_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. */ /* Warn for an integer constant that does not fit into integer type. */
else if (TREE_CODE (expr_type) == INTEGER_TYPE else if (TREE_CODE (expr_type) == INTEGER_TYPE
...@@ -2583,7 +2583,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2583,7 +2583,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
" constant value to negative integer"); " constant value to negative integer");
} }
else else
give_warning = true; give_warning = UNSAFE_OTHER;
} }
else if (TREE_CODE (type) == REAL_TYPE) else if (TREE_CODE (type) == REAL_TYPE)
{ {
...@@ -2592,7 +2592,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2592,7 +2592,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
{ {
REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr); REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
if (!exact_real_truncate (TYPE_MODE (type), &a)) 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 /* Warn for a real constant that does not fit into a smaller
real type. */ real type. */
...@@ -2601,7 +2601,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2601,7 +2601,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
{ {
REAL_VALUE_TYPE a = TREE_REAL_CST (expr); REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
if (!exact_real_truncate (TYPE_MODE (type), &a)) if (!exact_real_truncate (TYPE_MODE (type), &a))
give_warning = true; give_warning = UNSAFE_REAL;
} }
} }
} }
...@@ -2610,7 +2610,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2610,7 +2610,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
/* Warn for real types converted to integer types. */ /* Warn for real types converted to integer types. */
if (TREE_CODE (expr_type) == REAL_TYPE if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE) && TREE_CODE (type) == INTEGER_TYPE)
give_warning = true; give_warning = UNSAFE_REAL;
else if (TREE_CODE (expr_type) == INTEGER_TYPE else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == INTEGER_TYPE) && TREE_CODE (type) == INTEGER_TYPE)
...@@ -2648,7 +2648,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2648,7 +2648,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
&& int_fits_type_p (op1, c_common_signed_type (type)) && int_fits_type_p (op1, c_common_signed_type (type))
&& int_fits_type_p (op1, && int_fits_type_p (op1,
c_common_unsigned_type (type)))) c_common_unsigned_type (type))))
return false; return SAFE_CONVERSION;
/* If constant is unsigned and fits in the target /* If constant is unsigned and fits in the target
type, then the result will also fit. */ type, then the result will also fit. */
else if ((TREE_CODE (op0) == INTEGER_CST else if ((TREE_CODE (op0) == INTEGER_CST
...@@ -2657,12 +2657,12 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2657,12 +2657,12 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
|| (TREE_CODE (op1) == INTEGER_CST || (TREE_CODE (op1) == INTEGER_CST
&& unsigned1 && unsigned1
&& int_fits_type_p (op1, type))) && int_fits_type_p (op1, type)))
return false; return SAFE_CONVERSION;
} }
} }
/* Warn for integer types converted to smaller integer types. */ /* Warn for integer types converted to smaller integer types. */
if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) if (TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true; give_warning = UNSAFE_OTHER;
/* When they are the same width but different signedness, /* When they are the same width but different signedness,
then the value may change. */ then the value may change. */
...@@ -2698,14 +2698,14 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns) ...@@ -2698,14 +2698,14 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
|| !exact_real_truncate (TYPE_MODE (type), &real_high_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. */ /* Warn for real types converted to smaller real types. */
else if (TREE_CODE (expr_type) == REAL_TYPE else if (TREE_CODE (expr_type) == REAL_TYPE
&& TREE_CODE (type) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE
&& TYPE_PRECISION (type) < TYPE_PRECISION (expr_type)) && TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
give_warning = true; give_warning = UNSAFE_REAL;
} }
return give_warning; return give_warning;
...@@ -2719,8 +2719,9 @@ conversion_warning (tree type, tree expr) ...@@ -2719,8 +2719,9 @@ conversion_warning (tree type, tree expr)
{ {
tree expr_type = TREE_TYPE (expr); tree expr_type = TREE_TYPE (expr);
location_t loc = EXPR_LOC_OR_HERE (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; return;
switch (TREE_CODE (expr)) switch (TREE_CODE (expr))
...@@ -2747,7 +2748,12 @@ conversion_warning (tree type, tree expr) ...@@ -2747,7 +2748,12 @@ conversion_warning (tree type, tree expr)
case REAL_CST: case REAL_CST:
case INTEGER_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, warning_at (loc, OPT_Wconversion,
"conversion to %qT alters %qT constant value", "conversion to %qT alters %qT constant value",
type, expr_type); type, expr_type);
...@@ -2766,7 +2772,12 @@ conversion_warning (tree type, tree expr) ...@@ -2766,7 +2772,12 @@ conversion_warning (tree type, tree expr)
} }
default: /* 'expr' is not a constant. */ 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, warning_at (loc, OPT_Wconversion,
"conversion to %qT from %qT may alter its value", "conversion to %qT from %qT may alter its value",
type, expr_type); type, expr_type);
......
...@@ -688,6 +688,16 @@ struct visibility_flags ...@@ -688,6 +688,16 @@ struct visibility_flags
unsigned inlines_hidden : 1; /* True when -finlineshidden in effect. */ 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. */ /* Global visibility options. */
extern struct visibility_flags visibility_options; extern struct visibility_flags visibility_options;
...@@ -741,7 +751,7 @@ extern tree c_common_signed_type (tree); ...@@ -741,7 +751,7 @@ extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree); extern tree c_common_signed_or_unsigned_type (int, tree);
extern void c_common_init_ts (void); extern void c_common_init_ts (void);
extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); 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 bool decl_with_nonnull_addr_p (const_tree);
extern tree c_fully_fold (tree, bool, bool *); extern tree c_fully_fold (tree, bool, bool *);
extern tree decl_constant_value_for_optimization (tree); extern tree decl_constant_value_for_optimization (tree);
......
...@@ -387,6 +387,10 @@ Werror-implicit-function-declaration ...@@ -387,6 +387,10 @@ Werror-implicit-function-declaration
C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration) C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration)
This switch is deprecated; use -Werror=implicit-function-declaration instead 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 Wfloat-equal
C ObjC C++ ObjC++ Var(warn_float_equal) Warning C ObjC C++ ObjC++ Var(warn_float_equal) Warning
Warn if testing floating point numbers for equality Warn if testing floating point numbers for equality
......
...@@ -262,7 +262,8 @@ Objective-C and Objective-C++ Dialects}. ...@@ -262,7 +262,8 @@ Objective-C and Objective-C++ Dialects}.
-Wpointer-arith -Wno-pointer-to-int-cast @gol -Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wredundant-decls -Wno-return-local-addr @gol -Wredundant-decls -Wno-return-local-addr @gol
-Wreturn-type -Wsequence-point -Wshadow @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 -Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol
-Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
-Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
...@@ -4592,6 +4593,14 @@ value, like assigning a signed integer expression to an unsigned ...@@ -4592,6 +4593,14 @@ value, like assigning a signed integer expression to an unsigned
integer variable. An explicit cast silences the warning. In C, this integer variable. An explicit cast silences the warning. In C, this
option is enabled also by @option{-Wconversion}. 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 @item -Wsizeof-pointer-memaccess
@opindex Wsizeof-pointer-memaccess @opindex Wsizeof-pointer-memaccess
@opindex Wno-sizeof-pointer-memaccess @opindex Wno-sizeof-pointer-memaccess
......
2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com>
PR c/53001
* 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 conversions that are warned about by
-Wfloat-conversion.
2013-11-19 Martin Jambor <mjambor@suse.cz> 2013-11-19 Martin Jambor <mjambor@suse.cz>
PR rtl-optimization/59099 PR rtl-optimization/59099
......
/* Test for diagnostics for Wconversion for floating-point. */
/* { dg-do compile } */
/* { 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 to 'float' alters 'double' constant value" } */
vfloat = 3.1; /* { dg-warning "conversion to 'float' alters 'double' constant value" } */
ffloat (3.1L); /* { dg-warning "conversion to 'float' alters 'long double' constant value" } */
vfloat = 3.1L; /* { dg-warning "conversion to 'float' alters 'long double' constant value" } */
fdouble (3.1L); /* { dg-warning "conversion to 'double' alters 'long double' constant value" "" { target large_long_double } } */
vdouble = 3.1L; /* { dg-warning "conversion to 'double' alters 'long double' constant value" "" { target large_long_double } } */
ffloat (vdouble); /* { dg-warning "conversion to 'float' from 'double' may alter its value" } */
vfloat = vdouble; /* { dg-warning "conversion to 'float' from 'double' may alter its value" } */
ffloat (vlongdouble); /* { dg-warning "conversion to 'float' from 'long double' may alter its value" } */
vfloat = vlongdouble; /* { dg-warning "conversion to 'float' from 'long double' may alter its value" } */
fdouble (vlongdouble); /* { dg-warning "conversion to 'double' from 'long double' may alter its value" "" { target large_long_double } } */
vdouble = vlongdouble; /* { dg-warning "conversion to 'double' from 'long double' may alter its value" "" { target large_long_double } } */
fsi (3.1f); /* { dg-warning "conversion to 'int' alters 'float' constant value" } */
si = 3.1f; /* { dg-warning "conversion to 'int' alters 'float' constant value" } */
fsi (3.1); /* { dg-warning "conversion to 'int' alters 'double' constant value" } */
si = 3.1; /* { dg-warning "conversion to 'int' alters 'double' constant value" } */
fsi (d); /* { dg-warning "conversion to 'int' from 'double' may alter its value" } */
si = d; /* { dg-warning "conversion to 'int' from 'double' may alter its value" } */
ffloat (INT_MAX); /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
vfloat = INT_MAX; /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
ffloat (16777217); /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
vfloat = 16777217; /* { dg-warning "conversion to 'float' alters 'int' constant value" } */
sc = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion to 'signed char' alters 'double' constant value" } */
uc = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion to 'unsigned char' alters 'double' constant value" } */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment