| Issue |
204085
|
| Summary |
[clang] constexpr `__builtin_mul_overflow` returns wrong result for non-byte-aligned `_BitInt(N)`
|
| Labels |
|
| Assignees |
|
| Reporter |
xroche
|
## Summary
At compile time, `__builtin_mul_overflow` returns the wrong result for `_BitInt(N)` operands when N is not a multiple of 8 (e.g. `_BitInt(13)`). The runtime path is correct. Already fixed on trunk by PR #192568 (merged 2026-04-23); Clang 21 and 22 releases still ship the bug.
## Reproducer
https://godbolt.org/z/dbnbeafbf
```cpp
constexpr signed _BitInt(13) f() {
signed _BitInt(13) r;
__builtin_mul_overflow((signed _BitInt(13))-2, (signed _BitInt(13))3, &r);
return r;
}
static_assert(f() == (signed _BitInt(13))-6);
```
Clang 21 and 22 reject the static_assert:
```
error: static assertion failed due to requirement 'f() == (_BitInt(13))-6'
note: _expression_ evaluates to '-6 == -6'
```
The diagnostic prints `-6 == -6` and the assertion still fires: the compile-time multiplication stores its result at the storage width (16 bits for `_BitInt(13)`) instead of the integer width (13 bits), so the value does not compare equal to a freshly-constructed `_BitInt(13)` value of -6.
## Impact
`std::saturating_{add,sub,mul}` in libc++ and any C++ code calling `__builtin_*_overflow` with `_BitInt(N)` operands at compile time silently produce wrong values on Clang 21 and 22.
## Fix
[PR #192568](https://github.com/llvm/llvm-project/pull/192568) replaced `getTypeSize(ResultType)` with `getIntWidth(ResultType)` in `clang/lib/AST/ExprConstant.cpp`. Will ship in Clang 23.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs