+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
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)
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
}
}
}
+
+ 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. */
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;
}
&& 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;
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,
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",
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
--- /dev/null
+/* 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" } */
+}
+
--- /dev/null
+/* 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" } */
+}
+