Hi!

This paper from what I can see mostly just codifies our
implementation-defined behavior as standard (two's complement as the only
possible representation of signed integers, but still keeping UB signed
integer overflows), the only changes I found that IMHO need changing
in GCC are that left shifts of signed integers are now always well defined
(well, like for unsigned shifts out of bounds shift count is still UB),
so we need to accept such shifts in constant expressions, don't warn about
those and don't sanitize it in ubsan when in -std=c++2a or -std=gnu++2a
modes.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-11-14  Jakub Jelinek  <ja...@redhat.com>

        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.

--- gcc/cp/constexpr.c.jj       2018-11-08 18:07:56.071075133 +0100
+++ gcc/cp/constexpr.c  2018-11-14 08:56:23.705641740 +0100
@@ -1920,9 +1920,14 @@ cxx_eval_check_shift_p (location_t loc,
      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)
        {
--- gcc/c-family/c-warn.c.jj    2018-08-27 17:50:41.649525026 +0200
+++ gcc/c-family/c-warn.c       2018-11-14 08:59:02.424022594 +0100
@@ -2286,6 +2286,8 @@ diagnose_mismatched_attributes (tree old
 /* Warn if signed left shift overflows.  We don't warn
    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>
+   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 lo
   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 lo
    * 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)
--- gcc/c-family/c-ubsan.c.jj   2018-11-14 00:55:32.351645152 +0100
+++ gcc/c-family/c-ubsan.c      2018-11-14 08:35:13.131600599 +0100
@@ -134,7 +134,10 @@ ubsan_instrument_shift (location_t loc,
   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:
--- gcc/doc/invoke.texi.jj      2018-11-14 00:55:36.636576201 +0100
+++ gcc/doc/invoke.texi 2018-11-14 13:05:54.055418228 +0100
@@ -5074,11 +5074,12 @@ This is the warning level of @option{-Ws
 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
--- gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C.jj    2018-11-14 
09:11:57.355234640 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-shift1.C       2018-11-14 
09:10:58.382207816 +0100
@@ -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
--- gcc/testsuite/g++.dg/warn/permissive-1.C.jj 2016-01-12 19:22:56.760037087 
+0100
+++ gcc/testsuite/g++.dg/warn/permissive-1.C    2018-11-14 09:36:47.658634223 
+0100
@@ -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 } } }
--- gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C.jj    2017-11-21 
20:22:57.851043093 +0100
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-shift1.C       2018-11-14 
09:14:31.240695295 +0100
@@ -19,18 +19,18 @@ constexpr int i2 = fn2 (1, 200); // { dg
 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)
--- gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C.jj     2017-11-21 
20:22:57.870042857 +0100
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-60049.C        2018-11-14 
09:35:29.599922164 +0100
@@ -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
 
 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" }
--- gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C.jj       2014-10-22 
15:52:16.527879247 +0200
+++ gcc/testsuite/g++.dg/ubsan/cxx11-shift-1.C  2018-11-14 08:43:15.806640709 
+0100
@@ -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);
 }
--- gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C.jj       2014-04-23 
10:18:41.089330171 +0200
+++ gcc/testsuite/g++.dg/ubsan/cxx11-shift-2.C  2018-11-14 08:43:07.947770370 
+0100
@@ -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'" } */
--- gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C.jj       2018-11-14 
08:35:13.132600583 +0100
+++ gcc/testsuite/g++.dg/ubsan/cxx2a-shift-1.C  2018-11-14 08:42:56.229963690 
+0100
@@ -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);
+}
--- gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C.jj       2018-11-14 
08:35:13.132600583 +0100
+++ gcc/testsuite/g++.dg/ubsan/cxx2a-shift-2.C  2018-11-14 08:42:48.803086219 
+0100
@@ -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);
+}

        Jakub

Reply via email to