From 8ee099430b5d72050380f7506520d3bcb52b2f41 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 14 Nov 2018 17:46:06 +0100 Subject: [PATCH] P1236R1 - Signed integers are two's complement P1236R1 - Signed integers are two's complement gcc/cp/ * constexpr.c (cxx_eval_check_shift_p): Disable the signed LSHIFT_EXPR checks for c++2a. gcc/c-family/ * c-warn.c (maybe_warn_shift_overflow): Don't warn for c++2a. * c-ubsan.c (ubsan_instrument_shift): Make signed shifts with in-range second operand well defined for -std=c++2a. gcc/ * doc/invoke.texi (Wshift-overflow): Adjust documentation for c++2a. gcc/testsuite/ * g++.dg/cpp2a/constexpr-shift1.C: New test. * g++.dg/warn/permissive-1.C (enum A, enum D): Don't expect diagnostics here for c++2a. * g++.dg/cpp0x/constexpr-shift1.C (fn3, i3, fn4, i4): Don't expect diagnostics here for c++2a. * g++.dg/cpp0x/constexpr-60049.C (f3, x3, y3): Likewise. * g++.dg/ubsan/cxx11-shift-1.C (main): Add some further tests. * g++.dg/ubsan/cxx11-shift-2.C (main): Likewise. * g++.dg/ubsan/cxx2a-shift-1.C: New test. * g++.dg/ubsan/cxx2a-shift-2.C: New test. From-SVN: r266153 --- gcc/ChangeLog | 4 +++ gcc/c-family/ChangeLog | 5 ++++ gcc/c-family/c-ubsan.c | 5 +++- gcc/c-family/c-warn.c | 6 +++-- gcc/cp/ChangeLog | 6 +++++ gcc/cp/constexpr.c | 11 +++++--- gcc/doc/invoke.texi | 5 ++-- gcc/testsuite/ChangeLog | 14 +++++++++++ gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C | 6 ++--- gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C | 8 +++--- gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C | 25 +++++++++++++++++++ gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C | 7 +++--- gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C | 13 ++++++++-- gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C | 11 ++++++++ gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C | 15 +++++++++++ gcc/testsuite/g++.dg/warn/permissive-1.C | 4 +-- 16 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C create mode 100644 gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C create mode 100644 gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ae27a137d15..fb28a7d585a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,9 @@ 2018-11-14 Jakub Jelinek + P1236R1 - Signed integers are two's complement + * doc/invoke.texi (Wshift-overflow): Adjust documentation for + c++2a. + PR bootstrap/86739 * hash-map.h (hash_map::iterator::reference_pair): New class. (hash_map::iterator::operator*): Return it rather than std::pair. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 94b823fe398..eadad496156 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,5 +1,10 @@ 2018-11-14 Jakub Jelinek + P1236R1 - Signed integers are two's complement + * c-warn.c (maybe_warn_shift_overflow): Don't warn for c++2a. + * c-ubsan.c (ubsan_instrument_shift): Make signed shifts + with in-range second operand well defined for -std=c++2a. + PR other/88007 * c-common.c (parse_optimize_options): Allocate option string from opts_obstack rather than as GC memory. Move the allocation after diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c index ae6e25043bf..4ef2bd80cfe 100644 --- a/gcc/c-family/c-ubsan.c +++ b/gcc/c-family/c-ubsan.c @@ -134,7 +134,10 @@ ubsan_instrument_shift (location_t loc, enum tree_code code, if (TYPE_OVERFLOW_WRAPS (type0) || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)), TYPE_PRECISION (type0)) - || !sanitize_flags_p (SANITIZE_SHIFT_BASE)) + || !sanitize_flags_p (SANITIZE_SHIFT_BASE) + /* In C++2a and later, shifts are well defined except when + the second operand is not within bounds. */ + || cxx_dialect >= cxx2a) ; /* For signed x << y, in C99/C11, the following: diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index a1a7f935964..93c343a4384 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -2286,6 +2286,8 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl) /* Warn if signed left shift overflows. We don't warn about left-shifting 1 into the sign bit in C++14; cf. + and don't warn for C++2a at all, as signed left shifts never + overflow. LOC is a location of the shift; OP0 and OP1 are the operands. Return true if an overflow is detected, false otherwise. */ @@ -2300,7 +2302,7 @@ maybe_warn_shift_overflow (location_t loc, tree op0, tree op1) unsigned int prec0 = TYPE_PRECISION (type0); /* Left-hand operand must be signed. */ - if (TYPE_UNSIGNED (type0)) + if (TYPE_UNSIGNED (type0) || cxx_dialect >= cxx2a) return false; unsigned int min_prec = (wi::min_precision (wi::to_wide (op0), SIGNED) @@ -2309,7 +2311,7 @@ maybe_warn_shift_overflow (location_t loc, tree op0, tree op1) * However, shifting 1 _out_ of the sign bit, as in * INT_MIN << 1, is considered an overflow. */ - if (!tree_int_cst_sign_bit(op0) && min_prec == prec0 + 1) + if (!tree_int_cst_sign_bit (op0) && min_prec == prec0 + 1) { /* Never warn for C++14 onwards. */ if (cxx_dialect >= cxx14) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1587b49e7dd..ee5c2ce8446 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2018-11-14 Jakub Jelinek + + P1236R1 - Signed integers are two's complement + * constexpr.c (cxx_eval_check_shift_p): Disable the signed LSHIFT_EXPR + checks for c++2a. + 2018-11-13 David Malcolm * call.c: Replace "source_location" with "location_t". diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 7b696da5834..a50e186148d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1920,9 +1920,14 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx, if E1 has a signed type and non-negative value, and E1x2^E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; - otherwise, the behavior is undefined. */ - if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (lhstype) - && (cxx_dialect >= cxx11)) + otherwise, the behavior is undefined. + For C++2a: + The value of E1 << E2 is the unique value congruent to E1 x 2^E2 modulo + 2^N, where N is the range exponent of the type of the result. */ + if (code == LSHIFT_EXPR + && !TYPE_UNSIGNED (lhstype) + && cxx_dialect >= cxx11 + && cxx_dialect < cxx2a) { if (tree_int_cst_sgn (lhs) == -1) { diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 283d20fa296..ea730b61c05 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5074,11 +5074,12 @@ This is the warning level of @option{-Wshift-overflow} and is enabled by default in C99 and C++11 modes (and newer). This warning level does not warn about left-shifting 1 into the sign bit. (However, in C, such an overflow is still rejected in contexts where an integer constant expression -is required.) +is required.) No warning is emitted in C++2A mode (and newer), as signed left +shifts always wrap. @item -Wshift-overflow=2 This warning level also warns about left-shifting 1 into the sign bit, -unless C++14 mode is active. +unless C++14 mode (or newer) is active. @end table @item -Wswitch diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cee33796cc5..a94cb786840 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2018-11-14 Jakub Jelinek + + P1236R1 - Signed integers are two's complement + * g++.dg/cpp2a/constexpr-shift1.C: New test. + * g++.dg/warn/permissive-1.C (enum A, enum D): Don't expect + diagnostics here for c++2a. + * g++.dg/cpp0x/constexpr-shift1.C (fn3, i3, fn4, i4): Don't expect + diagnostics here for c++2a. + * g++.dg/cpp0x/constexpr-60049.C (f3, x3, y3): Likewise. + * g++.dg/ubsan/cxx11-shift-1.C (main): Add some further tests. + * g++.dg/ubsan/cxx11-shift-2.C (main): Likewise. + * g++.dg/ubsan/cxx2a-shift-1.C: New test. + * g++.dg/ubsan/cxx2a-shift-2.C: New test. + 2018-11-14 Jeff Law * gcc.c-torture/compile/20181114.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C index 172963f1fc4..8400910f051 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C @@ -5,7 +5,7 @@ constexpr int f1 (int n) { return 1 << n; } // { dg-error "shift expression" } constexpr int f2 (int n) { return 1 << n; } // { dg-error "shift expression" } -constexpr int f3 (int n) { return n << 1; } // { dg-error "shift expression" } +constexpr int f3 (int n) { return n << 1; } // { dg-error "shift expression" "" { target c++17_down } } constexpr int f4 (int n) { return 1 >> n; } // { dg-error "shift expression" } constexpr int f5 (int n) { return 1 >> n; } // { dg-error "shift expression" } @@ -13,12 +13,12 @@ constexpr int X = __CHAR_BIT__ * sizeof (int) + 1; constexpr int x1 = f1 (X); // { dg-message "in .constexpr. expansion of" } constexpr int x2 = f2 (-1); // { dg-message "in .constexpr. expansion of" } -constexpr int x3 = f3 (-1); // { dg-message "in .constexpr. expansion of" } +constexpr int x3 = f3 (-1); // { dg-message "in .constexpr. expansion of" "" { target c++17_down } } constexpr int x4 = f4 (X); // { dg-message "in .constexpr. expansion of" } constexpr int x5 = f5 (-1); // { dg-message "in .constexpr. expansion of" } constexpr int y1 = 1 << X; // { dg-error "shift expression" } constexpr int y2 = 1 << -1; // { dg-error "shift expression" } -constexpr int y3 = -1 << 1; // { dg-error "shift expression" } +constexpr int y3 = -1 << 1; // { dg-error "shift expression" "" { target c++17_down } } constexpr int y4 = 1 >> X; // { dg-error "shift expression" } constexpr int y5 = 1 >> -1; // { dg-error "shift expression" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C index 4abd9e0cfb6..c1cfb1eebdb 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C @@ -19,18 +19,18 @@ constexpr int i2 = fn2 (1, 200); // { dg-message "in .constexpr. expansion of " constexpr int fn3 (int i, int j) { - return i << j; // { dg-error "is negative" } + return i << j; // { dg-error "is negative" "" { target c++17_down } } } -constexpr int i3 = fn3 (-1, 2); // { dg-message "in .constexpr. expansion of " } +constexpr int i3 = fn3 (-1, 2); // { dg-message "in .constexpr. expansion of " "" { target c++17_down } } constexpr int fn4 (int i, int j) { - return i << j; // { dg-error "overflows" } + return i << j; // { dg-error "overflows" "" { target c++17_down } } } -constexpr int i4 = fn4 (__INT_MAX__, 2); // { dg-message "in .constexpr. expansion of " } +constexpr int i4 = fn4 (__INT_MAX__, 2); // { dg-message "in .constexpr. expansion of " "" { target c++17_down } } constexpr int fn5 (int i, int j) diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C new file mode 100644 index 00000000000..abe15e721db --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++11 } } + +constexpr int a = -42 << 0; // { dg-error "left operand of shift expression '\\(-42 << 0\\)' is negative" "" { target c++17_down } } +constexpr int b = -42 << 1; // { dg-error "left operand of shift expression '\\(-42 << 1\\)' is negative" "" { target c++17_down } } +constexpr int c = -42 << (__SIZEOF_INT__ * __CHAR_BIT__ - 1); // { dg-error "left operand of shift expression '\\(-42 << \[0-9]*\\)' is negative" "" { target c++17_down } } + // { dg-warning "result of '\\(-42 << \[0-9]*\\)' requires \[0-9]* bits to represent, but 'int' only has \[0-9]* bits" "" { target c++17_down } .-1 } +constexpr int d = 42 << (__SIZEOF_INT__ * __CHAR_BIT__ - 1); // { dg-error "shift expression '\\(42 << \[0-9]*\\)' overflows" "" { target c++17_down } } + // { dg-warning "result of '\\(42 << \[0-9]*\\)' requires \[0-9]* bits to represent, but 'int' only has \[0-9]* bits" "" { target c++17_down } .-1 } +constexpr int e = 32 << (__SIZEOF_INT__ * __CHAR_BIT__ - 5); // { dg-error "shift expression '\\(32 << \[0-9]*\\)' overflows" "" { target c++17_down } } + // { dg-warning "result of '\\(32 << \[0-9]*\\)' requires \[0-9]* bits to represent, but 'int' only has \[0-9]* bits" "" { target c++17_down } .-1 } +constexpr int f = 32 << (__SIZEOF_INT__ * __CHAR_BIT__ - 6); +constexpr int g = -42U << 0; +constexpr int h = -42U << 1; +constexpr int i = -42U << (__SIZEOF_INT__ * __CHAR_BIT__ - 1); +constexpr int j = 42U << (__SIZEOF_INT__ * __CHAR_BIT__ - 1); +constexpr int k = 32U << (__SIZEOF_INT__ * __CHAR_BIT__ - 5); +constexpr int l = 32U << (__SIZEOF_INT__ * __CHAR_BIT__ - 6); +#if __cplusplus > 201703L +static_assert (a == g); +static_assert (b == h); +static_assert (c == i); +static_assert (d == j); +static_assert (e == k); +static_assert (f == l); +#endif diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C index 431eab12d3e..7e998885c9f 100644 --- a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C +++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C @@ -2,9 +2,10 @@ /* { dg-options "-fsanitize=shift -w -fno-sanitize-recover=shift -std=c++11" } */ int -main (void) +main () { int a = 1; - a <<= 31; - return 0; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 1); + a = 16; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 5); } diff --git a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C index fbc16dfd3d8..d104ead4175 100644 --- a/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C +++ b/gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C @@ -2,9 +2,18 @@ /* { dg-options "-fsanitize=shift -w -std=c++11" } */ int -main (void) +main () { int a = -42; a <<= 1; + a = -43; + a <<= 0; + a = -44; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 1); + a = 32; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 3); } -/* { dg-output "left shift of negative value -42" } */ +/* { dg-output "left shift of negative value -42.*" } */ +/* { dg-output "left shift of negative value -43.*" } */ +/* { dg-output "left shift of negative value -44.*" } */ +/* { dg-output "left shift of 32 by \[0-9]* places cannot be represented in type 'int'" } */ diff --git a/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C b/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C new file mode 100644 index 00000000000..2094cb1b6b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C @@ -0,0 +1,11 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover=shift -std=c++2a" } */ + +int +main () +{ + int a = 1; + a <<= 31; + a = 16; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 5); +} diff --git a/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C b/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C new file mode 100644 index 00000000000..5a5641068f7 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C @@ -0,0 +1,15 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover=shift -std=c++2a" } */ + +int +main () +{ + int a = -42; + a <<= 1; + a = -43; + a <<= 0; + a = -44; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 1); + a = 32; + a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 3); +} diff --git a/gcc/testsuite/g++.dg/warn/permissive-1.C b/gcc/testsuite/g++.dg/warn/permissive-1.C index bfaca763782..387af606b26 100644 --- a/gcc/testsuite/g++.dg/warn/permissive-1.C +++ b/gcc/testsuite/g++.dg/warn/permissive-1.C @@ -2,7 +2,7 @@ // { dg-do compile { target int32 } } // { dg-options "-fpermissive -Wno-shift-overflow -Wno-shift-count-overflow -Wno-shift-count-negative" } -enum A { AA = -1 << 4 }; // { dg-warning "operand of shift expression" "" { target c++11 } } +enum A { AA = -1 << 4 }; // { dg-warning "operand of shift expression" "" { target { c++11 && c++17_down } } } enum B { BB = 1 << -4 }; // { dg-warning "operand of shift expression" } enum C { CC = 1 << __SIZEOF_INT__ * 4 * __CHAR_BIT__ - 4 }; // { dg-warning "operand of shift expression" } -enum D { DD = 10 << __SIZEOF_INT__ * __CHAR_BIT__ - 2 }; // { dg-warning "shift expression" "" { target c++11 } } +enum D { DD = 10 << __SIZEOF_INT__ * __CHAR_BIT__ - 2 }; // { dg-warning "shift expression" "" { target { c++11 && c++17_down } } } -- 2.30.2