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

Reply via email to