aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-warn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family/c-warn.c')
-rw-r--r--gcc/c-family/c-warn.c70
1 files changed, 61 insertions, 9 deletions
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 6dbc660..d8f0ad6 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -1155,17 +1155,18 @@ check_main_parameter_types (tree decl)
"%q+D declared as variadic function", decl);
}
-/* Warns if the conversion of EXPR to TYPE may alter a value.
+/* Warns and returns true if the conversion of EXPR to TYPE may alter a value.
This is a helper function for warnings_for_convert_and_check. */
-static void
+static bool
conversion_warning (location_t loc, tree type, tree expr, tree result)
{
tree expr_type = TREE_TYPE (expr);
enum conversion_safety conversion_kind;
+ bool is_arith = false;
if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
- return;
+ return false;
/* This may happen, because for LHS op= RHS we preevaluate
RHS and create C_MAYBE_CONST_EXPR <SAVE_EXPR <RHS>>, which
@@ -1195,7 +1196,7 @@ conversion_warning (location_t loc, tree type, tree expr, tree result)
if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
warning_at (loc, OPT_Wconversion,
"conversion to %qT from boolean expression", type);
- return;
+ return true;
case REAL_CST:
case INTEGER_CST:
@@ -1250,8 +1251,48 @@ conversion_warning (location_t loc, tree type, tree expr, tree result)
warning_at (loc, warnopt,
"conversion from %qT to %qT changes the value of %qE",
expr_type, type, expr);
- break;
+ return true;
}
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case TRUNC_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case TRUNC_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case RDIV_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (conversion_warning (loc, type, op0, result)
+ || conversion_warning (loc, type, op1, result))
+ return true;
+ goto arith_op;
+ }
+
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case NON_LVALUE_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ {
+ /* Unary ops or binary ops for which we only care about the lhs. */
+ tree op0 = TREE_OPERAND (expr, 0);
+ if (conversion_warning (loc, type, op0, result))
+ return true;
+ goto arith_op;
+ }
+
case COND_EXPR:
{
/* In case of COND_EXPR, we do not care about the type of
@@ -1259,12 +1300,16 @@ conversion_warning (location_t loc, tree type, tree expr, tree result)
tree op1 = TREE_OPERAND (expr, 1);
tree op2 = TREE_OPERAND (expr, 2);
- conversion_warning (loc, type, op1, result);
- conversion_warning (loc, type, op2, result);
- return;
+ return (conversion_warning (loc, type, op1, result)
+ || conversion_warning (loc, type, op2, result));
}
- default: /* 'expr' is not a constant. */
+ arith_op:
+ /* We didn't warn about the operands, we might still want to warn if
+ -Warith-conversion. */
+ is_arith = true;
+ gcc_fallthrough ();
+ default:
conversion_kind = unsafe_conversion_p (loc, type, expr, result, true);
{
int warnopt;
@@ -1276,6 +1321,11 @@ conversion_warning (location_t loc, tree type, tree expr, tree result)
warnopt = OPT_Wconversion;
else
break;
+ if (is_arith
+ && global_dc->option_enabled (warnopt,
+ global_dc->lang_mask,
+ global_dc->option_state))
+ warnopt = OPT_Warith_conversion;
if (conversion_kind == UNSAFE_SIGN)
warning_at (loc, warnopt, "conversion to %qT from %qT "
"may change the sign of the result",
@@ -1288,8 +1338,10 @@ conversion_warning (location_t loc, tree type, tree expr, tree result)
warning_at (loc, warnopt,
"conversion from %qT to %qT may change value",
expr_type, type);
+ return true;
}
}
+ return false;
}
/* Produce warnings after a conversion. RESULT is the result of