------- Comment #8 from manu at gcc dot gnu dot org 2008-02-15 18:04 ------- This patch fixes this bug but it is an ugly hack. Perhaps such an ugly hack is the only thing we can do at the moment.
Once bootstrapping + testing finishes, I will submit. Index: gcc/c-common.c =================================================================== --- gcc/c-common.c (revision 132310) +++ gcc/c-common.c (working copy) @@ -1270,65 +1270,98 @@ conversion_warning (tree type, tree expr "conversion to %qT alters %qT constant value", type, TREE_TYPE (expr)); } else /* 'expr' is not a constant. */ { + tree expr_type = TREE_TYPE (expr); + /* Warn for real types converted to integer types. */ - if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE + if (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == INTEGER_TYPE) give_warning = true; - else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + else if (TREE_CODE (expr_type) == INTEGER_TYPE && TREE_CODE (type) == INTEGER_TYPE) { /* Don't warn about unsigned char y = 0xff, x = (int) y; */ expr = get_unwidened (expr, 0); + expr_type = TREE_TYPE (expr); + /* Don't warn for short y; short x = ((int)y & 0xff); */ + if (TREE_CODE (expr) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST) + { + int unsigned0, unsigned1; + tree arg0, arg1; + tree tmp_type; + tree op0, op1; + + op0 = convert (expr_type, TREE_OPERAND (expr, 0)); + op1 = convert (expr_type, TREE_OPERAND (expr, 1)); + + arg0 = get_narrower (op0, &unsigned0); + arg1 = get_narrower (op1, &unsigned1); + + /* Handle the case that OP0 (or OP1) does not *contain* a conversion + but it *requires* conversion to TYPE. */ + if ((TYPE_PRECISION (TREE_TYPE (op0)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && TREE_TYPE (op0) != expr_type) + unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (expr_type) + && (tmp_type + = c_common_signed_or_unsigned_type (unsigned0, + TREE_TYPE (arg0))) + && !POINTER_TYPE_P (tmp_type) + && int_fits_type_p (arg1, tmp_type)) + expr_type = tmp_type; + } /* Warn for integer types converted to smaller integer types. */ - if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))) + if (formal_prec < TYPE_PRECISION (expr_type)) give_warning = true; /* When they are the same width but different signedness, then the value may change. */ - else if ((formal_prec == TYPE_PRECISION (TREE_TYPE (expr)) - && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type)) + else if ((formal_prec == TYPE_PRECISION (expr_type) + && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type)) /* Even when converted to a bigger type, if the type is unsigned but expr is signed, then negative values will be changed. */ - || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr)))) + || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type))) warning (OPT_Wsign_conversion, "conversion to %qT from %qT may change the sign of the result", - type, TREE_TYPE (expr)); + type, expr_type); } /* Warn for integer types converted to real types if and only if all the range of values of the integer type cannot be represented by the real type. */ - else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + else if (TREE_CODE (expr_type) == INTEGER_TYPE && TREE_CODE (type) == REAL_TYPE) { - tree type_low_bound = TYPE_MIN_VALUE (TREE_TYPE (expr)); - tree type_high_bound = TYPE_MAX_VALUE (TREE_TYPE (expr)); + tree type_low_bound = TYPE_MIN_VALUE (expr_type); + tree type_high_bound = TYPE_MAX_VALUE (expr_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); if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound) || !exact_real_truncate (TYPE_MODE (type), &real_high_bound)) give_warning = true; } /* Warn for real types converted to smaller real types. */ - else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE + else if (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE - && formal_prec < TYPE_PRECISION (TREE_TYPE (expr))) + && formal_prec < TYPE_PRECISION (expr_type)) give_warning = true; if (give_warning) warning (OPT_Wconversion, "conversion to %qT from %qT may alter its value", - type, TREE_TYPE (expr)); + type, expr_type); } } /* Produce warnings after a conversion. RESULT is the result of converting EXPR to TYPE. This is a helper function for -- manu at gcc dot gnu dot org changed: What |Removed |Added ---------------------------------------------------------------------------- Last reconfirmed|2007-12-13 21:38:26 |2008-02-15 18:04:44 date| | http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34389