https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82547
--- Comment #1 from Andrew Macleod <amacleod at redhat dot com> --- On a further note, this appears to be because wide_int tries not to use all the words is it can sign extend? the sequence with the issue is: Mn = wi::min_value (128, UNSIGNED); Mx = wi::max_value (128, UNSIGNED); Mxminus2 = wi::sub (Mx, 2, UNSIGNED, &ov); x = wi::sub (Mn, Mxminus2 , UNSIGNED, &ov2); fprintf (stderr, "ov %d ov2 %d\n", ov, ov2); if I look at Mn, I see: (gdb) p Mn.dump() [...,0], precision = 128 (gdb) p Mn $14 = {<wide_int_storage> = {val = {0, 140737488344128, 34794152}, len = 1, precision = 128}, static is_sign_extended = <optimized out>} So the precision is 128, but len is set to 1 on a 64 bit host. Same thing happens for Mx. Then when wi::sub_large is called, it does the calculation and checks: if (len * HOST_BITS_PER_WIDE_INT < prec) { val[len] = mask0 - mask1 - borrow; len++; if (overflow) *overflow = false; } Since both values have a len of 1, and precision is 128, it decides there cannot be an overflow. It seems to be ignoring that fgact that sign-extension may exist. Interestingly, if I remove that entire hunk of code, and and let it do the general check for overflow which follows, It works as I would expect. Of course, I have no idea what the side effects of that are... I leave it in the hands of a wide_int expert.