aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-01-07 12:20:26 -0500
committerJason Merrill <jason@redhat.com>2020-01-21 18:40:19 -0500
commitc77074d05691053ee7347d9e44ab89b3adb23fb1 (patch)
tree589e55a7c74bb1c0ec4c46ac228f20340158909a /gcc/c-family
parent731dbfc3f3b586e78f2ccdca24561ea3369c6338 (diff)
downloadgcc-c77074d05691053ee7347d9e44ab89b3adb23fb1.zip
gcc-c77074d05691053ee7347d9e44ab89b3adb23fb1.tar.gz
gcc-c77074d05691053ee7347d9e44ab89b3adb23fb1.tar.bz2
PR c++/40752 - useless -Wconversion with short +=.
This is a longstanding issue with lots of duplicates; people are not interested in a -Wconversion warning about mychar += 1. So now that warning depends on -Warith-conversion; otherwise we only warn if operands of the arithmetic have conversion issues. * c.opt (-Warith-conversion): New. * c-warn.c (conversion_warning): Recurse for operands of operators. Only warn about the whole expression with -Warith-conversion.
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog9
-rw-r--r--gcc/c-family/c-warn.c70
-rw-r--r--gcc/c-family/c.opt4
3 files changed, 74 insertions, 9 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index fbbc924..3a9ce24 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,4 +1,13 @@
2020-01-21 Jason Merrill <jason@redhat.com>
+ Manuel López-Ibáñez <manu@gcc.gnu.org>
+
+ PR c++/40752 - useless -Wconversion with short +=.
+ * c.opt (-Warith-conversion): New.
+ * c-warn.c (conversion_warning): Recurse for operands of
+ operators. Only warn about the whole expression with
+ -Warith-conversion.
+
+2020-01-21 Jason Merrill <jason@redhat.com>
* c-common.c (unsafe_conversion_p): Don't warn, return UNSAFE_SIGN.
* c-warn.c (conversion_warning): Warn about UNSAFE_SIGN.
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
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index aa0fa5d..814ed17 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1107,6 +1107,10 @@ Wshift-negative-value
C ObjC C++ ObjC++ Var(warn_shift_negative_value) Init(-1) Warning
Warn if left shifting a negative value.
+Warith-conversion
+C ObjC C++ ObjC++ Var(warn_arith_conv) Warning
+Warn if conversion of the result of arithmetic might change the value even though converting the operands cannot.
+
Wsign-compare
C ObjC C++ ObjC++ Var(warn_sign_compare) Warning LangEnabledBy(C++ ObjC++,Wall)
Warn about signed-unsigned comparisons.