From 0173bd2a038cbeef871b22b312a6856ab1dcda2a Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 7 May 2015 19:36:31 +0000 Subject: [PATCH] re PR c/65179 (Introduce new C warning: -Wshift-negative-value) PR c/65179 * c-common.c (c_fully_fold_internal): Warn when left shifting a negative value. * c.opt (Wshift-negative-value): New option. * c-opts.c (c_common_post_options): Set warn_shift_negative_value when -Wextra and C99/C++11 mode. * c-typeck.c (build_binary_op): Warn when left shifting a negative value. * typeck.c (cp_build_binary_op): Warn when left shifting a negative value. * doc/invoke.texi: Document -Wshift-negative-value. * c-c++-common/Wshift-negative-value-1.c: New test. * testsuite/c-c++-common/Wshift-negative-value-2.c: New test. * testsuite/c-c++-common/Wshift-negative-value-3.c: New test. * testsuite/c-c++-common/Wshift-negative-value-4.c: New test. * testsuite/c-c++-common/Wshift-negative-value-5.c: New test. * testsuite/c-c++-common/Wshift-negative-value-6.c: New test. * testsuite/gcc.dg/c90-left-shift-1.c: New test. * testsuite/gcc.dg/c99-const-expr-7.c: Add dg-error. * testsuite/gcc.dg/c99-left-shift-1.c: New test. From-SVN: r222889 --- gcc/ChangeLog | 5 ++ gcc/c-family/ChangeLog | 9 ++++ gcc/c-family/c-common.c | 8 +++ gcc/c-family/c-opts.c | 5 ++ gcc/c-family/c.opt | 4 ++ gcc/c/ChangeLog | 6 +++ gcc/c/c-typeck.c | 11 ++++ gcc/cp/ChangeLog | 6 +++ gcc/cp/typeck.c | 9 ++++ gcc/doc/invoke.texi | 9 +++- gcc/testsuite/ChangeLog | 13 +++++ .../c-c++-common/Wshift-negative-value-1.c | 49 ++++++++++++++++++ .../c-c++-common/Wshift-negative-value-2.c | 49 ++++++++++++++++++ .../c-c++-common/Wshift-negative-value-3.c | 49 ++++++++++++++++++ .../c-c++-common/Wshift-negative-value-4.c | 49 ++++++++++++++++++ .../c-c++-common/Wshift-negative-value-5.c | 50 +++++++++++++++++++ .../c-c++-common/Wshift-negative-value-6.c | 50 +++++++++++++++++++ gcc/testsuite/gcc.dg/c90-left-shift-1.c | 12 +++++ gcc/testsuite/gcc.dg/c99-const-expr-7.c | 2 +- gcc/testsuite/gcc.dg/c99-left-shift-1.c | 12 +++++ 20 files changed, 405 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-1.c create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-2.c create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-3.c create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-4.c create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-5.c create mode 100644 gcc/testsuite/c-c++-common/Wshift-negative-value-6.c create mode 100644 gcc/testsuite/gcc.dg/c90-left-shift-1.c create mode 100644 gcc/testsuite/gcc.dg/c99-left-shift-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f9735014b63..f1c685aa8d8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2015-05-07 Marek Polacek + + PR c/65179 + * doc/invoke.texi: Document -Wshift-negative-value. + 2015-05-06 Aditya Kumar * gcov-tool.c (do_merge): Refactore to remove int ret. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index dd69f258406..6f141215c29 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2015-05-07 Marek Polacek + + PR c/65179 + * c-common.c (c_fully_fold_internal): Warn when left shifting a + negative value. + * c.opt (Wshift-negative-value): New option. + * c-opts.c (c_common_post_options): Set warn_shift_negative_value + when -Wextra and C99/C++11 mode. + 2015-05-07 Marek Polacek Martin Uecker diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ada8e8aa901..378f2373345 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -1361,6 +1361,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, && !TREE_OVERFLOW_P (op0) && !TREE_OVERFLOW_P (op1)) overflow_warning (EXPR_LOCATION (expr), ret); + if (code == LSHIFT_EXPR + && TREE_CODE (orig_op0) != INTEGER_CST + && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE + && TREE_CODE (op0) == INTEGER_CST + && c_inhibit_evaluation_warnings == 0 + && tree_int_cst_sgn (op0) < 0) + warning_at (loc, OPT_Wshift_negative_value, + "left shift of negative value"); if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR) && TREE_CODE (orig_op1) != INTEGER_CST && TREE_CODE (op1) == INTEGER_CST diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 1a67b5a766d..a61d6a857d8 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -866,6 +866,11 @@ c_common_post_options (const char **pfilename) if (warn_implicit_int == -1) warn_implicit_int = flag_isoc99; + /* -Wshift-negative-value is enabled by -Wextra in C99 and C++11 modes. */ + if (warn_shift_negative_value == -1) + warn_shift_negative_value = (extra_warnings + && (cxx_dialect >= cxx11 || flag_isoc99)); + /* Declone C++ 'structors if -Os. */ if (flag_declone_ctor_dtor == -1) flag_declone_ctor_dtor = optimize_size; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 8ef0cea52fd..48947b4f2b4 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -781,6 +781,10 @@ Wshift-count-overflow C ObjC C++ ObjC++ Var(warn_shift_count_overflow) Init(1) Warning Warn if shift count >= width of type +Wshift-negative-value +C ObjC C++ ObjC++ Var(warn_shift_negative_value) Init(-1) Warning +Warn if left shifting a negative value + Wsign-compare C ObjC C++ ObjC++ Var(warn_sign_compare) Warning LangEnabledBy(C++ ObjC++,Wall) Warn about signed-unsigned comparisons diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 2ef895a639c..ccd1e7291cf 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2015-05-07 Marek Polacek + + PR c/65179 + * c-typeck.c (build_binary_op): Warn when left shifting a negative + value. + 2015-04-30 Marek Polacek * c-typeck.c (set_init_label): Call error_at instead of error and diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 328f294899b..73275aa106b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -10697,6 +10697,17 @@ build_binary_op (location_t location, enum tree_code code, && code1 == INTEGER_TYPE) { doing_shift = true; + if (TREE_CODE (op0) == INTEGER_CST + && tree_int_cst_sgn (op0) < 0) + { + /* Don't reject a left shift of a negative value in a context + where a constant expression is needed in C90. */ + if (flag_isoc99) + int_const = false; + if (c_inhibit_evaluation_warnings == 0) + warning_at (location, OPT_Wshift_negative_value, + "left shift of negative value"); + } if (TREE_CODE (op1) == INTEGER_CST) { if (tree_int_cst_sgn (op1) < 0) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4929faabfd5..3c32e6f77dd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2015-05-07 Marek Polacek + + PR c/65179 + * typeck.c (cp_build_binary_op): Warn when left shifting a negative + value. + 2015-05-07 Jason Merrill DR 1467 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 91db32a7da9..549e4b161f5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4326,11 +4326,20 @@ cp_build_binary_op (location_t location, } else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) { + tree const_op0 = fold_non_dependent_expr (op0); + if (TREE_CODE (const_op0) != INTEGER_CST) + const_op0 = op0; tree const_op1 = fold_non_dependent_expr (op1); if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; doing_shift = true; + if (TREE_CODE (const_op0) == INTEGER_CST + && tree_int_cst_sgn (const_op0) < 0 + && (complain & tf_warning) + && c_inhibit_evaluation_warnings == 0) + warning (OPT_Wshift_negative_value, + "left shift of negative value"); if (TREE_CODE (const_op1) == INTEGER_CST) { if (tree_int_cst_lt (const_op1, integer_zero_node)) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 2c58a0d76ca..934edd6efae 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -271,7 +271,7 @@ Objective-C and Objective-C++ Dialects}. -Wpointer-arith -Wno-pointer-to-int-cast @gol -Wredundant-decls -Wno-return-local-addr @gol -Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol --Wshift-count-negative -Wshift-count-overflow @gol +-Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol -Wsign-compare -Wsign-conversion -Wfloat-conversion @gol -Wsizeof-pointer-memaccess -Wsizeof-array-argument @gol -Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol @@ -3489,6 +3489,7 @@ name is still supported, but the newer name is more descriptive.) -Wsign-compare @gol -Wtype-limits @gol -Wuninitialized @gol +-Wshift-negative-value @gol -Wunused-parameter @r{(only with} @option{-Wunused} @r{or} @option{-Wall}@r{)} @gol -Wunused-but-set-parameter @r{(only with} @option{-Wunused} @r{or} @option{-Wall}@r{)} @gol } @@ -3922,6 +3923,12 @@ Warn if shift count is negative. This warning is enabled by default. @opindex Wno-shift-count-overflow Warn if shift count >= width of type. This warning is enabled by default. +@item -Wshift-negative-value +@opindex Wshift-negative-value +@opindex Wno-shift-negative-value +Warn if left shifting a negative value. This warning is enabled by +@option{-Wextra} in C99 and C++11 modes (and newer). + @item -Wswitch @opindex Wswitch @opindex Wno-switch diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1bacc3e6d8e..4ffc42857ef 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2015-05-07 Marek Polacek + + PR c/65179 + * c-c++-common/Wshift-negative-value-1.c: New test. + * testsuite/c-c++-common/Wshift-negative-value-2.c: New test. + * testsuite/c-c++-common/Wshift-negative-value-3.c: New test. + * testsuite/c-c++-common/Wshift-negative-value-4.c: New test. + * testsuite/c-c++-common/Wshift-negative-value-5.c: New test. + * testsuite/c-c++-common/Wshift-negative-value-6.c: New test. + * testsuite/gcc.dg/c90-left-shift-1.c: New test. + * testsuite/gcc.dg/c99-const-expr-7.c: Add dg-error. + * testsuite/gcc.dg/c99-left-shift-1.c: New test. + 2015-05-07 Segher Boessenkool PR middle-end/192 diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c new file mode 100644 index 00000000000..5d803ade8d1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c @@ -0,0 +1,49 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wextra" } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, /* { dg-warning "left shift of negative value|not an integer constant" } */ + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-warning "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-warning "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c new file mode 100644 index 00000000000..fc89af1ba4b --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c @@ -0,0 +1,49 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wshift-negative-value" } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, /* { dg-warning "left shift of negative value" } */ + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-warning "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-warning "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c new file mode 100644 index 00000000000..bf9b1a07bb7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c @@ -0,0 +1,49 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wextra -Wno-shift-negative-value" } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-bogus "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-bogus "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c new file mode 100644 index 00000000000..85fbd0e3525 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c @@ -0,0 +1,49 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-bogus "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-bogus "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c new file mode 100644 index 00000000000..74ecd1e2867 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-5.c @@ -0,0 +1,50 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wshift-negative-value" } */ +/* { dg-additional-options "-std=c++03" { target c++ } } */ +/* { dg-additional-options "-std=c90" { target c } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, /* { dg-warning "left shift of negative value" } */ + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-warning "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-warning "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-6.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-6.c new file mode 100644 index 00000000000..de9db528cb8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-6.c @@ -0,0 +1,50 @@ +/* PR c/65179 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wextra" } */ +/* { dg-additional-options "-std=c++03" { target c++ } } */ +/* { dg-additional-options "-std=c90" { target c } } */ + +enum E { + A = 0 << 1, + B = 1 << 1, + C = -1 << 1, /* { dg-bogus "left shift of negative value" } */ + D = 0 >> 1, + E = 1 >> 1, + F = -1 >> 1 +}; + +int +left (int x) +{ + /* Warn for LSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z << x; + r += o << x; + r += m << x; /* { dg-bogus "left shift of negative value" } */ + r += 0 << x; + r += 1 << x; + r += -1 << x; /* { dg-bogus "left shift of negative value" } */ + r += -1U << x; + return r; +} + +int +right (int x) +{ + /* Shouldn't warn for RSHIFT_EXPR. */ + const int z = 0; + const int o = 1; + const int m = -1; + int r = 0; + r += z >> x; + r += o >> x; + r += m >> x; + r += 0 >> x; + r += 1 >> x; + r += -1 >> x; + r += -1U >> x; + return r; +} diff --git a/gcc/testsuite/gcc.dg/c90-left-shift-1.c b/gcc/testsuite/gcc.dg/c90-left-shift-1.c new file mode 100644 index 00000000000..755595f5c27 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-left-shift-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */ + +enum E { A = -2 << 1 }; +int i = -1 << 0; + +int +f (int i) +{ + switch (i) + case -1 << 0: break; +} diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-7.c b/gcc/testsuite/gcc.dg/c99-const-expr-7.c index b872077e964..75b05677ce1 100644 --- a/gcc/testsuite/gcc.dg/c99-const-expr-7.c +++ b/gcc/testsuite/gcc.dg/c99-const-expr-7.c @@ -30,8 +30,8 @@ int f1 = (0 ? 0 << -1 : 0); int g1 = (0 ? 0 >> 1000 : 0); int h1 = (0 ? 0 >> -1: 0); -/* Allowed for now, but actually undefined behavior in C99. */ int i = -1 << 0; +/* { dg-error "constant" "constant" { target *-*-* } 33 } */ int j[1] = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 36 } */ diff --git a/gcc/testsuite/gcc.dg/c99-left-shift-1.c b/gcc/testsuite/gcc.dg/c99-left-shift-1.c new file mode 100644 index 00000000000..9a73049fa22 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-left-shift-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */ + +enum E { A = -2 << 1 }; /* { dg-error "constant expression" } */ +int i = -1 << 0; /* { dg-error "constant expression" } */ + +int +f (int i) +{ + switch (i) + case -1 << 0: break; /* { dg-error "constant expression" } */ +} -- 2.30.2