Commit 7a37fa90 by Mikhail Maltsev Committed by Mikhail Maltsev

re PR c/48956 (-Wconversion should warn when a complex value is assigned to a real result)

PR c/48956

gcc/c-family/
* c-common.c (int_safely_convertible_to_real_p): Define.
(unsafe_conversion_p): Check conversions involving complex types.
(conversion_warning): Add new warning message for conversions which
discard imaginary component.
* c-common.h: (enum conversion_safety): Add new enumerator for such
conversions.

gcc/testsuite/
* gcc.dg/Wconversion-complex-c99.c: New test.
* gcc.dg/Wconversion-complex-gnu.c: New test.

From-SVN: r223223
parent bc4315fb
2015-05-15 Mikhail Maltsev <maltsevm@gmail.com>
PR c/48956
* c-common.c (int_safely_convertible_to_real_p): Define.
(unsafe_conversion_p): Check conversions involving complex types.
(conversion_warning): Add new warning message for conversions which
discard imaginary component.
* c-common.h: (enum conversion_safety): Add new enumerator for such
conversions.
2015-05-14 Marek Polacek <polacek@redhat.com> 2015-05-14 Marek Polacek <polacek@redhat.com>
PR c/66066 PR c/66066
......
...@@ -2707,17 +2707,42 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise) ...@@ -2707,17 +2707,42 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
return result_type; return result_type;
} }
/* Checks if expression EXPR of real/integer type cannot be converted /* Returns true iff any integer value of type FROM_TYPE can be represented as
to the real/integer type TYPE. Function returns non-zero when: real of type TO_TYPE. This is a helper function for unsafe_conversion_p. */
static bool
int_safely_convertible_to_real_p (const_tree from_type, const_tree to_type)
{
tree type_low_bound = TYPE_MIN_VALUE (from_type);
tree type_high_bound = TYPE_MAX_VALUE (from_type);
REAL_VALUE_TYPE real_low_bound =
real_value_from_int_cst (0, type_low_bound);
REAL_VALUE_TYPE real_high_bound =
real_value_from_int_cst (0, type_high_bound);
return exact_real_truncate (TYPE_MODE (to_type), &real_low_bound)
&& exact_real_truncate (TYPE_MODE (to_type), &real_high_bound);
}
/* Checks if expression EXPR of complex/real/integer type cannot be converted
to the complex/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, or both
complex.
* EXPR is not a constant of complex type and TYPE is a real or
an integer.
* EXPR is not a constant of real type and TYPE is an integer. * EXPR is not a constant of real type and TYPE is an integer.
* 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
can return SAFE_CONVERSION (zero) in that case. Function can produce can return SAFE_CONVERSION (zero) in that case. Function can produce
signedness warnings if PRODUCE_WARNS is true. */ signedness warnings if PRODUCE_WARNS is true.
Function allows conversions from complex constants to non-complex types,
provided that imaginary part is zero and real part can be safely converted
to TYPE. */
enum conversion_safety enum conversion_safety
unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns) unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
...@@ -2728,6 +2753,11 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns) ...@@ -2728,6 +2753,11 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST) if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
{ {
/* If type is complex, we are interested in compatibility with
underlying type. */
if (TREE_CODE (type) == COMPLEX_TYPE)
type = TREE_TYPE (type);
/* Warn for real constant that is not an exact integer converted /* Warn for real constant that is not an exact integer converted
to integer type. */ to integer type. */
if (TREE_CODE (expr_type) == REAL_TYPE if (TREE_CODE (expr_type) == REAL_TYPE
...@@ -2777,6 +2807,63 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns) ...@@ -2777,6 +2807,63 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
} }
} }
} }
else if (TREE_CODE (expr) == COMPLEX_CST)
{
tree imag_part = TREE_IMAGPART (expr);
/* Conversion from complex constant with zero imaginary part,
perform check for conversion of real part. */
if ((TREE_CODE (imag_part) == REAL_CST
&& real_zerop (imag_part))
|| (TREE_CODE (imag_part) == INTEGER_CST
&& integer_zerop (imag_part)))
/* Note: in this branch we use recursive call to unsafe_conversion_p
with different type of EXPR, but it is still safe, because when EXPR
is a constant, it's type is not used in text of generated warnings
(otherwise they could sound misleading). */
return unsafe_conversion_p (loc, type, TREE_REALPART (expr),
produce_warns);
/* Conversion from complex constant with non-zero imaginary part. */
else
{
/* Conversion to complex type.
Perform checks for both real and imaginary parts. */
if (TREE_CODE (type) == COMPLEX_TYPE)
{
/* Unfortunately, produce_warns must be false in two subsequent
calls of unsafe_conversion_p, because otherwise we could
produce strange "double" warnings, if both real and imaginary
parts have conversion problems related to signedness.
For example:
int32_t _Complex a = 0x80000000 + 0x80000000i;
Possible solution: add a separate function for checking
constants and combine result of two calls appropriately. */
enum conversion_safety re_safety =
unsafe_conversion_p (loc, type, TREE_REALPART (expr), false);
enum conversion_safety im_safety =
unsafe_conversion_p (loc, type, imag_part, false);
/* Merge the results into appropriate single warning. */
/* Note: this case includes SAFE_CONVERSION, i.e. success. */
if (re_safety == im_safety)
give_warning = re_safety;
else if (!re_safety && im_safety)
give_warning = im_safety;
else if (re_safety && !im_safety)
give_warning = re_safety;
else
give_warning = UNSAFE_OTHER;
}
/* Warn about conversion from complex to real or integer type. */
else
give_warning = UNSAFE_IMAGINARY;
}
}
/* Checks for remaining case: EXPR is not constant. */
else else
{ {
/* Warn for real types converted to integer types. */ /* Warn for real types converted to integer types. */
...@@ -2856,20 +2943,11 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns) ...@@ -2856,20 +2943,11 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
else if (TREE_CODE (expr_type) == INTEGER_TYPE else if (TREE_CODE (expr_type) == INTEGER_TYPE
&& TREE_CODE (type) == REAL_TYPE) && TREE_CODE (type) == REAL_TYPE)
{ {
tree type_low_bound, type_high_bound;
REAL_VALUE_TYPE real_low_bound, real_high_bound;
/* Don't warn about char y = 0xff; float x = (int) y; */ /* Don't warn about char y = 0xff; float x = (int) y; */
expr = get_unwidened (expr, 0); expr = get_unwidened (expr, 0);
expr_type = TREE_TYPE (expr); expr_type = TREE_TYPE (expr);
type_low_bound = TYPE_MIN_VALUE (expr_type); if (!int_safely_convertible_to_real_p (expr_type, type))
type_high_bound = TYPE_MAX_VALUE (expr_type);
real_low_bound = real_value_from_int_cst (0, type_low_bound);
real_high_bound = real_value_from_int_cst (0, type_high_bound);
if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
|| !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
give_warning = UNSAFE_OTHER; give_warning = UNSAFE_OTHER;
} }
...@@ -2878,6 +2956,58 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns) ...@@ -2878,6 +2956,58 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
&& 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 = UNSAFE_REAL; give_warning = UNSAFE_REAL;
/* Check conversion between two complex types. */
else if (TREE_CODE (expr_type) == COMPLEX_TYPE
&& TREE_CODE (type) == COMPLEX_TYPE)
{
/* Extract underlying types (i.e., type of real and imaginary
parts) of expr_type and type. */
tree from_type = TREE_TYPE (expr_type);
tree to_type = TREE_TYPE (type);
/* Warn for real types converted to integer types. */
if (TREE_CODE (from_type) == REAL_TYPE
&& TREE_CODE (to_type) == INTEGER_TYPE)
give_warning = UNSAFE_REAL;
/* Warn for real types converted to smaller real types. */
else if (TREE_CODE (from_type) == REAL_TYPE
&& TREE_CODE (to_type) == REAL_TYPE
&& TYPE_PRECISION (to_type) < TYPE_PRECISION (from_type))
give_warning = UNSAFE_REAL;
/* Check conversion for complex integer types. Here implementation
is simpler than for real-domain integers because it does not
involve sophisticated cases, such as bitmasks, casts, etc. */
else if (TREE_CODE (from_type) == INTEGER_TYPE
&& TREE_CODE (to_type) == INTEGER_TYPE)
{
/* Warn for integer types converted to smaller integer types. */
if (TYPE_PRECISION (to_type) < TYPE_PRECISION (from_type))
give_warning = UNSAFE_OTHER;
/* Check for different signedness, see case for real-domain
integers (above) for a more detailed comment. */
else if (((TYPE_PRECISION (to_type) == TYPE_PRECISION (from_type)
&& TYPE_UNSIGNED (to_type) != TYPE_UNSIGNED (from_type))
|| (TYPE_UNSIGNED (to_type) && !TYPE_UNSIGNED (from_type)))
&& produce_warns)
warning_at (loc, OPT_Wsign_conversion,
"conversion to %qT from %qT "
"may change the sign of the result",
type, expr_type);
}
else if (TREE_CODE (from_type) == INTEGER_TYPE
&& TREE_CODE (to_type) == REAL_TYPE
&& !int_safely_convertible_to_real_p (from_type, to_type))
give_warning = UNSAFE_OTHER;
}
/* Warn for complex types converted to real or integer types. */
else if (TREE_CODE (expr_type) == COMPLEX_TYPE
&& TREE_CODE (type) != COMPLEX_TYPE)
give_warning = UNSAFE_IMAGINARY;
} }
return give_warning; return give_warning;
...@@ -2927,6 +3057,7 @@ conversion_warning (location_t loc, tree type, tree expr) ...@@ -2927,6 +3057,7 @@ conversion_warning (location_t loc, tree type, tree expr)
case REAL_CST: case REAL_CST:
case INTEGER_CST: case INTEGER_CST:
case COMPLEX_CST:
conversion_kind = unsafe_conversion_p (loc, type, expr, true); conversion_kind = unsafe_conversion_p (loc, type, expr, true);
if (conversion_kind == UNSAFE_REAL) if (conversion_kind == UNSAFE_REAL)
warning_at (loc, OPT_Wfloat_conversion, warning_at (loc, OPT_Wfloat_conversion,
...@@ -2956,6 +3087,10 @@ conversion_warning (location_t loc, tree type, tree expr) ...@@ -2956,6 +3087,10 @@ conversion_warning (location_t loc, tree type, tree expr)
warning_at (loc, OPT_Wfloat_conversion, warning_at (loc, OPT_Wfloat_conversion,
"conversion to %qT from %qT may alter its value", "conversion to %qT from %qT may alter its value",
type, expr_type); type, expr_type);
else if (conversion_kind == UNSAFE_IMAGINARY)
warning_at (loc, OPT_Wconversion,
"conversion to %qT from %qT discards imaginary component",
type, expr_type);
else if (conversion_kind) 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",
......
...@@ -728,15 +728,22 @@ struct visibility_flags ...@@ -728,15 +728,22 @@ 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. /* These enumerators are possible types of unsafe conversions. */
SAFE_CONVERSION The conversion is safe enum conversion_safety {
UNSAFE_OTHER Another type of conversion with problems /* The conversion is safe. */
UNSAFE_SIGN Conversion between signed and unsigned integers SAFE_CONVERSION = 0,
which are all warned about immediately, so this is unused /* Another type of conversion with problems. */
UNSAFE_REAL Conversions that reduce the precision of reals UNSAFE_OTHER,
including conversions from reals to integers /* Conversion between signed and unsigned integers
*/ which are all warned about immediately, so this is unused. */
enum conversion_safety { SAFE_CONVERSION = 0, UNSAFE_OTHER, UNSAFE_SIGN, UNSAFE_REAL }; UNSAFE_SIGN,
/* Conversions that reduce the precision of reals including conversions
from reals to integers. */
UNSAFE_REAL,
/* Conversions from complex to reals or integers, that discard imaginary
component. */
UNSAFE_IMAGINARY
};
/* Global visibility options. */ /* Global visibility options. */
extern struct visibility_flags visibility_options; extern struct visibility_flags visibility_options;
......
2015-05-15 Mikhail Maltsev <maltsevm@gmail.com>
PR c/48956
* gcc.dg/Wconversion-complex-c99.c: New test.
* gcc.dg/Wconversion-complex-gnu.c: New test.
2015-05-15 Marc Glisse <marc.glisse@inria.fr> 2015-05-15 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/64454 PR tree-optimization/64454
......
/* PR c/48956: Test for diagnostics for implicit conversions from complex
to real types and narrowing conversions of complex types. */
/* Architecture restrictions taken from Wconversion-real-integer.c.
Likewise, the magic value 16777217. */
/* { dg-do compile } */
/* { dg-skip-if "doubles are floats,ints are 16bits" { "avr-*-*" } { "*" } { "" } } */
/* { dg-options " -std=c99 -pedantic -Wconversion " } */
/* { dg-require-effective-target int32plus } */
/* { dg-require-effective-target double64plus } */
/* A number which does not fit into float. */
#define MAX_FLOAT_PLUS 16777217.
/* Other types could be added, but that won't affect test coverage. */
void ffloatc (float _Complex);
void fdoublec (double _Complex);
void ffloat (float);
void fdouble (double);
void fsi (int);
void fui (unsigned);
float _Complex vfloatc;
double _Complex vdoublec;
float vfloat;
double vdouble;
int vsi;
unsigned vui;
/* Check implicit conversions of complex values to reals. */
void
var_complex_to_real (void)
{
float _Complex floatc = 0.;
double _Complex doublec = 0.;
ffloatc (floatc);
fdoublec (doublec);
vfloatc = floatc;
vdoublec = doublec;
ffloat (floatc); /* { dg-warning "conversion" } */
fdouble (floatc); /* { dg-warning "conversion" } */
vfloat = floatc; /* { dg-warning "conversion" } */
vdouble = floatc; /* { dg-warning "conversion" } */
ffloat (doublec); /* { dg-warning "conversion" } */
fdouble (doublec); /* { dg-warning "conversion" } */
vfloat = doublec; /* { dg-warning "conversion" } */
vdouble = doublec; /* { dg-warning "conversion" } */
}
/* Check implicit narrowing conversions of complex values. */
void
var_complex_narrowing (void)
{
float _Complex floatc = 0.;
double _Complex doublec = 0.;
vdoublec = floatc;
vfloatc = doublec; /* { dg-warning "float-conversion" } */
fdoublec (floatc);
ffloatc (doublec); /* { dg-warning "float-conversion" } */
}
/* Check implicit conversions of complex values to integers. */
void
var_complex_to_int (void)
{
float _Complex floatc = 0.;
double _Complex doublec = 0.;
fsi (floatc); /* { dg-warning "conversion" } */
fui (floatc); /* { dg-warning "conversion" } */
vsi = floatc; /* { dg-warning "conversion" } */
vui = floatc; /* { dg-warning "conversion" } */
fsi (doublec); /* { dg-warning "conversion" } */
fui (doublec); /* { dg-warning "conversion" } */
vsi = doublec; /* { dg-warning "conversion" } */
vui = doublec; /* { dg-warning "conversion" } */
}
/* Check implicit conversion of constant complex values to floats. */
void
const_complex_to_real (void)
{
ffloat (__builtin_complex (0., 1.)); /* { dg-warning "conversion" } */
fdouble (__builtin_complex (0., 1.)); /* { dg-warning "conversion" } */
vfloat = __builtin_complex (0., 1.); /* { dg-warning "conversion" } */
vdouble = __builtin_complex (0., 1.); /* { dg-warning "conversion" } */
vfloat = __builtin_complex (1., 0.) + __builtin_complex (1., 0.);
vdouble = __builtin_complex (0., 0.) * __builtin_complex (1., 1.);
ffloat (__builtin_complex (1., 0.) + __builtin_complex (1., 0.));
fdouble (__builtin_complex (1., 0.) + __builtin_complex (1., 0.));
vfloat = __builtin_complex (MAX_FLOAT_PLUS, 0.); /* { dg-warning "float-conversion" } */
ffloat (__builtin_complex (MAX_FLOAT_PLUS, 0.)); /* { dg-warning "float-conversion" } */
}
/* Check implicit conversion of constant complex values to integers. */
void
const_complex_to_int (void)
{
vsi = __builtin_complex (-1., 0.);
vui = __builtin_complex (1., 0.);
fsi (__builtin_complex (-1., 0.));
fui (__builtin_complex (1., 0.));
vui = __builtin_complex (-1., 0.); /* { dg-warning "overflow" } */
fui (__builtin_complex (-1., 0.)); /* { dg-warning "overflow" } */
vsi = __builtin_complex (0.5, 0.); /* { dg-warning "float-conversion" } */
fui (__builtin_complex (0.5, 0.)); /* { dg-warning "float-conversion" } */
vsi = __builtin_complex (-0.5, 0.); /* { dg-warning "float-conversion" } */
fui (__builtin_complex (-0.5, 0.)); /* { dg-warning "float-conversion" } */
}
/* Check implicit narrowing conversion of constant complex values to. */
void
const_complex_narrowing (void)
{
ffloatc (__builtin_complex (-100., 100.));
ffloatc (__builtin_complex (MAX_FLOAT_PLUS, 0.)); /* { dg-warning "float-conversion" } */
ffloatc (__builtin_complex (0., MAX_FLOAT_PLUS)); /* { dg-warning "float-conversion" } */
ffloatc (__builtin_complex (MAX_FLOAT_PLUS, MAX_FLOAT_PLUS)); /* { dg-warning "float-conversion" } */
}
/* PR c/48956: Test for diagnostics for implicit conversions involving complex
types. See also Wconversion-complex-c99.c.
These tests cover integer complex values (which are GNU extensions). */
/* { dg-do compile } */
/* { dg-skip-if "doubles are floats,ints are 16bits" { "avr-*-*" } { "*" } { "" } } */
/* { dg-options " -std=gnu99 -Wconversion " } */
/* { dg-require-effective-target int32plus } */
/* { dg-require-effective-target double64plus } */
#include <limits.h>
void fsi (int);
void fui (unsigned);
void ffloat (float);
int vsi;
unsigned int vui;
float vfloat;
void fsic (int _Complex);
void fuic (unsigned _Complex);
void ffloatc (float _Complex);
int _Complex vsic;
unsigned _Complex vuic;
float _Complex vfloatc;
/* Check implicit conversions of float complex-domain values to integer
complex-domain types. */
void
var_float_to_int (void)
{
double _Complex doublec = 0.;
fsic (doublec); /* { dg-warning "float-conversion" } */
fuic (doublec); /* { dg-warning "float-conversion" } */
vsic = doublec; /* { dg-warning "float-conversion" } */
vuic = doublec; /* { dg-warning "float-conversion" } */
}
/* Check implicit conversions of integer complex-domain values to integer
real-domain types. */
void
var_complex_to_real (void)
{
int _Complex ic = 0;
unsigned _Complex uc = 0;
unsigned long long _Complex ullc = 0;
fsic (ic);
fuic (uc);
vsic = ic;
vuic = uc;
fsi (ic); /* { dg-warning "conversion" } */
vsi = ic; /* { dg-warning "conversion" } */
fui (uc); /* { dg-warning "conversion" } */
vui = uc; /* { dg-warning "conversion" } */
fuic (ullc); /* { dg-warning "conversion" } */
vuic = ullc; /* { dg-warning "conversion" } */
fui (ic); /* { dg-warning "conversion" } */
vui = ic; /* { dg-warning "conversion" } */
}
/* Check implicit conversions of float complex-domain constants to integer
types. */
void
const_float_to_int (void)
{
fsic (1. - 1.i);
fuic (1. + 1.i);
vsic = 1. - 1.i;
vuic = 1. + 1.i;
fsic (0.5 + 0.i); /* { dg-warning "float-conversion" } */
vsic = 0.5 + 0.i; /* { dg-warning "float-conversion" } */
fuic (0.5 + 0.i); /* { dg-warning "float-conversion" } */
}
/* Check implicit conversions of integer complex-domain constants to integer
types. */
void
const_complex_int_to_real_int (void)
{
fsi (-1 + 0i);
fui (1 + 0i);
vsi = -1 + 0i;
vui = 1 + 0i;
fui (1 + 1i); /* { dg-warning "conversion" } */
vui = 1 + 1i; /* { dg-warning "conversion" } */
fui (UINT_MAX + 1ull + 0i); /* { dg-warning "conversion" } */
vui = UINT_MAX + 1ull + 0i; /* { dg-warning "conversion" } */
ffloat (UINT_MAX + 0i); /* { dg-warning "float-conversion" } */
vfloat = UINT_MAX + 0i; /* { dg-warning "float-conversion" } */
}
void
const_complex_int_narrowing (void)
{
fsic (1 - 1i);
fuic (1 + 1i);
vsic = 1 - 1i;
vuic = 1 + 1i;
fuic (UINT_MAX + 1ull + 1i); /* { dg-warning "conversion" } */
fuic ((UINT_MAX + 1ull) * 1i); /* { dg-warning "conversion" } */
fuic ((UINT_MAX + 1ull) + (UINT_MAX + 1ull) * 1i); /* { dg-warning "conversion" } */
vuic = (UINT_MAX + 1ull) * 1i; /* { dg-warning "conversion" } */
vuic = (UINT_MAX + 1ull) + 1i; /* { dg-warning "conversion" } */
vuic = (UINT_MAX + 1ull) + (UINT_MAX + 1ull) * 1i; /* { dg-warning "conversion" } */
ffloatc (UINT_MAX * 1i); /* { dg-warning "float-conversion" } */
ffloatc (UINT_MAX + 1i); /* { dg-warning "float-conversion" } */
ffloatc (UINT_MAX + UINT_MAX * 1i); /* { dg-warning "float-conversion" } */
vfloatc = UINT_MAX * 1i; /* { dg-warning "float-conversion" } */
vfloatc = UINT_MAX + 1i; /* { dg-warning "float-conversion" } */
vfloatc = UINT_MAX + UINT_MAX * 1i; /* { dg-warning "float-conversion" } */
}
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