+2020-01-22 Jason Merrill <jason@redhat.com>
+
+ PR testsuite/93391 - PR 40752 test fails with unsigned plain char.
+ PR c++/40752
+ * c-warn.c (conversion_warning): Check operands only after checking
+ the whole expression. Don't check second operand of + for sign.
+
2020-01-21 Jason Merrill <jason@redhat.com>
Manuel López-Ibáñez <manu@gcc.gnu.org>
{
tree expr_type = TREE_TYPE (expr);
enum conversion_safety conversion_kind;
- bool is_arith = false;
+ int arith_ops = 0;
if (!warn_conversion && !warn_sign_conversion && !warn_float_conversion)
return false;
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;
- }
+ arith_ops = 2;
+ goto default_;
case PREDECREMENT_EXPR:
case PREINCREMENT_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;
- }
+ arith_ops = 1;
+ goto default_;
case COND_EXPR:
{
|| conversion_warning (loc, type, op2, result));
}
- arith_op:
- /* We didn't warn about the operands, we might still want to warn if
- -Warith-conversion. */
- is_arith = true;
- gcc_fallthrough ();
+ default_:
default:
conversion_kind = unsafe_conversion_p (type, expr, result, true);
{
warnopt = OPT_Wconversion;
else
break;
- if (is_arith
+
+ if (arith_ops
&& global_dc->option_enabled (warnopt,
global_dc->lang_mask,
global_dc->option_state))
- warnopt = OPT_Warith_conversion;
+ {
+ for (int i = 0; i < arith_ops; ++i)
+ {
+ tree op = TREE_OPERAND (expr, i);
+ tree opr = convert (type, op);
+ /* Avoid -Wsign-conversion for (unsigned)(x + (-1)). */
+ bool minus = TREE_CODE (expr) == PLUS_EXPR && i == 1;
+ if (unsafe_conversion_p (type, op, opr, !minus))
+ goto op_unsafe;
+ }
+ /* The operands seem safe, we might still want to warn if
+ -Warith-conversion. */
+ warnopt = OPT_Warith_conversion;
+ op_unsafe:;
+ }
+
if (conversion_kind == UNSAFE_SIGN)
warning_at (loc, warnopt, "conversion to %qT from %qT "
"may change the sign of the result",
c >>= (int)1;
c <<= (int)1;
c <<= c2;
- c += ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c += ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c += c2; /* { dg-warning "conversion" } */
- c -= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c -= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c -= c2; /* { dg-warning "conversion" } */
- c *= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c *= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c *= c2; /* { dg-warning "conversion" } */
- c /= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c /= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c /= c2; /* { dg-warning "conversion" } */
- c %= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c %= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c %= c2; /* { dg-warning "conversion" } */
c = ~c2; /* { dg-warning "conversion" } */
c = c2++; /* { dg-warning "conversion" } */
c >>= (int)1;
c <<= (int)1; /* { dg-warning "conversion" } */
c <<= c2; /* { dg-warning "conversion" } */
- c += ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c += ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c += c2; /* { dg-warning "conversion" } */
- c -= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c -= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c -= c2; /* { dg-warning "conversion" } */
- c *= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c *= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c *= c2; /* { dg-warning "conversion" } */
- c /= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c /= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c /= c2; /* { dg-warning "conversion" } */
- c %= ((int)SCHAR_MAX + SCHAR_MAX); /* { dg-warning "conversion" } */
+ c %= ((int)CHAR_MAX + CHAR_MAX); /* { dg-warning "conversion" } */
c %= c2; /* { dg-warning "conversion" } */
c = ~c2; /* { dg-warning "conversion" } */
c = c2++; /* { dg-warning "conversion" } */
--- /dev/null
+// PR c++/40752
+// { dg-additional-options -funsigned-char }
+
+#pragma GCC diagnostic error "-Wsign-conversion"
+void f(char *ar, int i)
+{
+ ar[i] -= 'a' - 'A';
+}