]> git.ipfire.org Git - thirdparty/gcc.git/commit
c, c++, c-family: -Wshift-negative-value and -Wshift-overflow* tweaks for -fwrapv...
authorJakub Jelinek <jakub@redhat.com>
Wed, 9 Mar 2022 08:15:28 +0000 (09:15 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 9 Mar 2022 08:15:28 +0000 (09:15 +0100)
commitd76511138dc816ef66fd16f71531f48c37dac3b4
tree52278f92631188e2f790f3858c83efd8a96998f5
parent7ca24ae5701769fccabf8cca4cad6987cb2187c6
c, c++, c-family: -Wshift-negative-value and -Wshift-overflow* tweaks for -fwrapv and C++20+ [PR104711]

As mentioned in the PR, different standards have different definition
on what is an UB left shift.  They all agree on out of bounds (including
negative) shift count.
The rules used by ubsan are:
C99-C2x ((unsigned) x >> (uprecm1 - y)) != 0 then UB
C++11-C++17 x < 0 || ((unsigned) x >> (uprecm1 - y)) > 1 then UB
C++20 and later everything is well defined
Now, for C++20, I've in the P1236R1 implementation added an early
exit for -Wshift-overflow* warning so that it never warns, but apparently
-Wshift-negative-value remained as is.  As it is well defined in C++20,
the following patch doesn't enable -Wshift-negative-value from -Wextra
anymore for C++20 and later, if users want for compatibility with C++17
and earlier get the warning, they still can by using -Wshift-negative-value
explicitly.
Another thing is -fwrapv, that is an extension to the standards, so it is up
to us how exactly we define that case.  Our ubsan code treats
TYPE_OVERFLOW_WRAPS (type0) and cxx_dialect >= cxx20 the same as only
diagnosing out of bounds shift count and nothing else and IMHO it is most
sensical to treat -fwrapv signed left shifts the same as C++20 treats
them, https://eel.is/c++draft/expr.shift#2
"The value of E1 << E2 is the unique value congruent to E1×2^E2 modulo 2^N,
where N is the width of the type of the result.
[Note 1: E1 is left-shifted E2 bit positions; vacated bits are zero-filled.
— end note]"
with no UB dependent on the E1 values.  The UB is only
"The behavior is undefined if the right operand is negative, or greater
than or equal to the width of the promoted left operand."
Under the hood (except for FEs and ubsan from FEs) GCC middle-end doesn't
consider UB in left shifts dependent on the first operand's value, only
the out of bounds shifts.

While this change isn't a regression, I'd think it is useful for GCC 12,
it doesn't add new warnings, but just removes warnings that aren't
appropriate.

2022-03-09  Jakub Jelinek  <jakub@redhat.com>

PR c/104711
gcc/
* doc/invoke.texi (-Wextra): Document that -Wshift-negative-value
is enabled by it only for C++11 to C++17 rather than for C++03 or
later.
(-Wshift-negative-value): Similarly (except here we stated
that it is enabled for C++11 or later).
gcc/c-family/
* c-opts.cc (c_common_post_options): Don't enable
-Wshift-negative-value from -Wextra for C++20 or later.
* c-ubsan.cc (ubsan_instrument_shift): Adjust comments.
* c-warn.cc (maybe_warn_shift_overflow): Use TYPE_OVERFLOW_WRAPS
instead of TYPE_UNSIGNED.
gcc/c/
* c-fold.cc (c_fully_fold_internal): Don't emit
-Wshift-negative-value warning if TYPE_OVERFLOW_WRAPS.
* c-typeck.cc (build_binary_op): Likewise.
gcc/cp/
* constexpr.cc (cxx_eval_check_shift_p): Use TYPE_OVERFLOW_WRAPS
instead of TYPE_UNSIGNED.
* typeck.cc (cp_build_binary_op): Don't emit
-Wshift-negative-value warning if TYPE_OVERFLOW_WRAPS.
gcc/testsuite/
* c-c++-common/Wshift-negative-value-1.c: Remove
dg-additional-options, instead in target selectors of each diagnostic
check for exact C++ versions where it should be diagnosed.
* c-c++-common/Wshift-negative-value-2.c: Likewise.
* c-c++-common/Wshift-negative-value-3.c: Likewise.
* c-c++-common/Wshift-negative-value-4.c: Likewise.
* c-c++-common/Wshift-negative-value-7.c: New test.
* c-c++-common/Wshift-negative-value-8.c: New test.
* c-c++-common/Wshift-negative-value-9.c: New test.
* c-c++-common/Wshift-negative-value-10.c: New test.
* c-c++-common/Wshift-overflow-1.c: Remove
dg-additional-options, instead in target selectors of each diagnostic
check for exact C++ versions where it should be diagnosed.
* c-c++-common/Wshift-overflow-2.c: Likewise.
* c-c++-common/Wshift-overflow-5.c: Likewise.
* c-c++-common/Wshift-overflow-6.c: Likewise.
* c-c++-common/Wshift-overflow-7.c: Likewise.
* c-c++-common/Wshift-overflow-8.c: New test.
* c-c++-common/Wshift-overflow-9.c: New test.
* c-c++-common/Wshift-overflow-10.c: New test.
* c-c++-common/Wshift-overflow-11.c: New test.
* c-c++-common/Wshift-overflow-12.c: New test.
26 files changed:
gcc/c-family/c-opts.cc
gcc/c-family/c-ubsan.cc
gcc/c-family/c-warn.cc
gcc/c/c-fold.cc
gcc/c/c-typeck.cc
gcc/cp/constexpr.cc
gcc/cp/typeck.cc
gcc/doc/invoke.texi
gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
gcc/testsuite/c-c++-common/Wshift-negative-value-10.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
gcc/testsuite/c-c++-common/Wshift-negative-value-7.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-negative-value-8.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-negative-value-9.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-overflow-1.c
gcc/testsuite/c-c++-common/Wshift-overflow-10.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-overflow-11.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-overflow-12.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-overflow-2.c
gcc/testsuite/c-c++-common/Wshift-overflow-5.c
gcc/testsuite/c-c++-common/Wshift-overflow-6.c
gcc/testsuite/c-c++-common/Wshift-overflow-7.c
gcc/testsuite/c-c++-common/Wshift-overflow-8.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wshift-overflow-9.c [new file with mode: 0644]