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>
PR c/66066
......
......@@ -2707,17 +2707,42 @@ shorten_binary_op (tree result_type, tree op0, tree op1, bool bitwise)
return result_type;
}
/* Checks if expression EXPR of real/integer type cannot be converted
to the real/integer type TYPE. Function returns non-zero when:
/* Returns true iff any integer value of type FROM_TYPE can be represented as
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 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 integer type which cannot be
exactly converted to real type.
Function allows conversions between types of different signedness and
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
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 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
to integer 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)
}
}
}
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
{
/* 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)
else if (TREE_CODE (expr_type) == INTEGER_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; */
expr = get_unwidened (expr, 0);
expr_type = TREE_TYPE (expr);
type_low_bound = TYPE_MIN_VALUE (expr_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))
if (!int_safely_convertible_to_real_p (expr_type, type))
give_warning = UNSAFE_OTHER;
}
......@@ -2878,6 +2956,58 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, bool produce_warns)
&& TREE_CODE (type) == REAL_TYPE
&& TYPE_PRECISION (type) < TYPE_PRECISION (expr_type))
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;
......@@ -2927,6 +3057,7 @@ conversion_warning (location_t loc, tree type, tree expr)
case REAL_CST:
case INTEGER_CST:
case COMPLEX_CST:
conversion_kind = unsafe_conversion_p (loc, type, expr, true);
if (conversion_kind == UNSAFE_REAL)
warning_at (loc, OPT_Wfloat_conversion,
......@@ -2956,6 +3087,10 @@ conversion_warning (location_t loc, tree type, tree expr)
warning_at (loc, OPT_Wfloat_conversion,
"conversion to %qT from %qT may alter its value",
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)
warning_at (loc, OPT_Wconversion,
"conversion to %qT from %qT may alter its value",
......
......@@ -728,15 +728,22 @@ 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 };
/* These enumerators are possible types of unsafe conversions. */
enum conversion_safety {
/* The conversion is safe. */
SAFE_CONVERSION = 0,
/* Another type of conversion with problems. */
UNSAFE_OTHER,
/* Conversion between signed and unsigned integers
which are all warned about immediately, so this is unused. */
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. */
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>
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