https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70733
liu zhenyu <lzy20000419 at outlook dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |lzy20000419 at outlook dot com
--- Comment #7 from liu zhenyu <lzy20000419 at outlook dot com> ---
Same lowered bit-field type leaking into C++ arithmetic, on the ++/-- path (and
the constexpr evaluator), not
only unary minus / unary plus.
```c++
struct S { long long w : 33; };
__attribute__((noipa)) int f (S *p) { long long a = p->w; p->w++; return p->w >
a; }
int main () { S s{4294967295LL}; if (f (&s) != 0 || s.w != -4294967296LL)
__builtin_abort (); return 0; }
```
```
$ g++ -O1 t.cc && ./a.out # Aborted (f returns 1)
```
-O0, `-fwrapv` and clang++ are fine. Per [conv.prom]p5 the field is not
promoted, so `p->w++` is
`p->w + 1` in `long long` (2^32, no overflow); storing into the 33-bit field
gives -2^32. GCC builds the
POSTINCREMENT in the lowered `<unnamed-signed:33>` type (`cp_build_unary_op`),
FRE then folds the compare to
true. Widths 33/40/63 (`long long`) and `__int128:70` fail; bit-fields not
wider than `int` are fine.
Constexpr rejects the same overflow:
```c++
constexpr long long f () { S s{4294967295LL}; s.w++; return s.w; }
constexpr long long r = f (); // error: overflow in constant expression
```
clang accepts (`-4294967296`). `p->w + 1`, `+=` and `=` already use the
declared type; only ++/-- (and unary
minus here) differ. Fixing those sites to use `unlowered_expr_type` would match
[conv.prom]p5.
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.