Commit 8ee09943 by Jakub Jelinek Committed by Jakub Jelinek

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
parent 12763abc
2018-11-14 Jakub Jelinek <jakub@redhat.com> 2018-11-14 Jakub Jelinek <jakub@redhat.com>
P1236R1 - Signed integers are two's complement
* doc/invoke.texi (Wshift-overflow): Adjust documentation for
c++2a.
PR bootstrap/86739 PR bootstrap/86739
* hash-map.h (hash_map::iterator::reference_pair): New class. * hash-map.h (hash_map::iterator::reference_pair): New class.
(hash_map::iterator::operator*): Return it rather than std::pair. (hash_map::iterator::operator*): Return it rather than std::pair.
2018-11-14 Jakub Jelinek <jakub@redhat.com> 2018-11-14 Jakub Jelinek <jakub@redhat.com>
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 PR other/88007
* c-common.c (parse_optimize_options): Allocate option string from * c-common.c (parse_optimize_options): Allocate option string from
opts_obstack rather than as GC memory. Move the allocation after opts_obstack rather than as GC memory. Move the allocation after
......
...@@ -134,7 +134,10 @@ ubsan_instrument_shift (location_t loc, enum tree_code code, ...@@ -134,7 +134,10 @@ ubsan_instrument_shift (location_t loc, enum tree_code code,
if (TYPE_OVERFLOW_WRAPS (type0) if (TYPE_OVERFLOW_WRAPS (type0)
|| maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)), || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)),
TYPE_PRECISION (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: /* For signed x << y, in C99/C11, the following:
......
...@@ -2286,6 +2286,8 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl) ...@@ -2286,6 +2286,8 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl)
/* Warn if signed left shift overflows. We don't warn /* Warn if signed left shift overflows. We don't warn
about left-shifting 1 into the sign bit in C++14; cf. about left-shifting 1 into the sign bit in C++14; cf.
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3367.html#1457> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3367.html#1457>
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. LOC is a location of the shift; OP0 and OP1 are the operands.
Return true if an overflow is detected, false otherwise. */ Return true if an overflow is detected, false otherwise. */
...@@ -2300,7 +2302,7 @@ maybe_warn_shift_overflow (location_t loc, tree op0, tree op1) ...@@ -2300,7 +2302,7 @@ maybe_warn_shift_overflow (location_t loc, tree op0, tree op1)
unsigned int prec0 = TYPE_PRECISION (type0); unsigned int prec0 = TYPE_PRECISION (type0);
/* Left-hand operand must be signed. */ /* Left-hand operand must be signed. */
if (TYPE_UNSIGNED (type0)) if (TYPE_UNSIGNED (type0) || cxx_dialect >= cxx2a)
return false; return false;
unsigned int min_prec = (wi::min_precision (wi::to_wide (op0), SIGNED) 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) ...@@ -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 * However, shifting 1 _out_ of the sign bit, as in
* INT_MIN << 1, is considered an overflow. * 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. */ /* Never warn for C++14 onwards. */
if (cxx_dialect >= cxx14) if (cxx_dialect >= cxx14)
......
2018-11-14 Jakub Jelinek <jakub@redhat.com>
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 <dmalcolm@redhat.com> 2018-11-13 David Malcolm <dmalcolm@redhat.com>
* call.c: Replace "source_location" with "location_t". * call.c: Replace "source_location" with "location_t".
......
...@@ -1920,9 +1920,14 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx, ...@@ -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 if E1 has a signed type and non-negative value, and E1x2^E2 is
representable in the corresponding unsigned type of the result type, representable in the corresponding unsigned type of the result type,
then that value, converted to the result type, is the resulting value; then that value, converted to the result type, is the resulting value;
otherwise, the behavior is undefined. */ otherwise, the behavior is undefined.
if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (lhstype) For C++2a:
&& (cxx_dialect >= cxx11)) 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) if (tree_int_cst_sgn (lhs) == -1)
{ {
......
...@@ -5074,11 +5074,12 @@ This is the warning level of @option{-Wshift-overflow} and is enabled ...@@ -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 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 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 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 @item -Wshift-overflow=2
This warning level also warns about left-shifting 1 into the sign bit, 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 @end table
@item -Wswitch @item -Wswitch
2018-11-14 Jakub Jelinek <jakub@redhat.com>
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 <law@redhat.com> 2018-11-14 Jeff Law <law@redhat.com>
* gcc.c-torture/compile/20181114.c: New test. * gcc.c-torture/compile/20181114.c: New test.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
constexpr int f1 (int n) { return 1 << n; } // { dg-error "shift expression" } 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 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 f4 (int n) { return 1 >> n; } // { dg-error "shift expression" }
constexpr int f5 (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; ...@@ -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 x1 = f1 (X); // { dg-message "in .constexpr. expansion of" }
constexpr int x2 = f2 (-1); // { 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 x4 = f4 (X); // { dg-message "in .constexpr. expansion of" }
constexpr int x5 = f5 (-1); // { 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 y1 = 1 << X; // { dg-error "shift expression" }
constexpr int y2 = 1 << -1; // { 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 y4 = 1 >> X; // { dg-error "shift expression" }
constexpr int y5 = 1 >> -1; // { dg-error "shift expression" } constexpr int y5 = 1 >> -1; // { dg-error "shift expression" }
...@@ -19,18 +19,18 @@ constexpr int i2 = fn2 (1, 200); // { dg-message "in .constexpr. expansion of " ...@@ -19,18 +19,18 @@ constexpr int i2 = fn2 (1, 200); // { dg-message "in .constexpr. expansion of "
constexpr int constexpr int
fn3 (int i, int j) 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 constexpr int
fn4 (int i, int j) 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 constexpr int
fn5 (int i, int j) fn5 (int i, int j)
......
// { 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
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
/* { dg-options "-fsanitize=shift -w -fno-sanitize-recover=shift -std=c++11" } */ /* { dg-options "-fsanitize=shift -w -fno-sanitize-recover=shift -std=c++11" } */
int int
main (void) main ()
{ {
int a = 1; int a = 1;
a <<= 31; a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 1);
return 0; a = 16;
a <<= (__SIZEOF_INT__ * __CHAR_BIT__ - 5);
} }
...@@ -2,9 +2,18 @@ ...@@ -2,9 +2,18 @@
/* { dg-options "-fsanitize=shift -w -std=c++11" } */ /* { dg-options "-fsanitize=shift -w -std=c++11" } */
int int
main (void) main ()
{ {
int a = -42; int a = -42;
a <<= 1; 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'" } */
/* { 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);
}
/* { 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);
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// { dg-do compile { target int32 } } // { dg-do compile { target int32 } }
// { dg-options "-fpermissive -Wno-shift-overflow -Wno-shift-count-overflow -Wno-shift-count-negative" } // { 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 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 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 } } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment