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>
* 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>
* c-opts.c: Include plugin.h.
......
......@@ -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
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.
......@@ -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
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);
......@@ -2562,7 +2562,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
&& 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
......@@ -2583,7 +2583,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
" constant value to negative integer");
}
else
give_warning = true;
give_warning = UNSAFE_OTHER;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
......@@ -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);
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. */
......@@ -2601,7 +2601,7 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
{
REAL_VALUE_TYPE a = TREE_REAL_CST (expr);
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)
/* 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)
......@@ -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_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
......@@ -2657,12 +2657,12 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
|| (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. */
......@@ -2698,14 +2698,14 @@ unsafe_conversion_p (tree type, tree expr, bool produce_warns)
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;
......@@ -2719,8 +2719,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))
......@@ -2747,7 +2748,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);
......@@ -2766,7 +2772,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);
......
......@@ -688,6 +688,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;
......@@ -741,7 +751,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);
......
......@@ -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
......
......@@ -262,7 +262,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
......@@ -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
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
......
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>
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