[libcxx-commits] [libcxx] a6fe3c7 - [libc++][test] Migrate _BitInt probe to __BITINT_MAXWIDTH__ and fix latent test bugs (#203876)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 19 05:30:38 PDT 2026


Author: Xavier Roche
Date: 2026-06-19T20:30:32+08:00
New Revision: a6fe3c7422db83346c336346e0b7a56ff084b17f

URL: https://github.com/llvm/llvm-project/commit/a6fe3c7422db83346c336346e0b7a56ff084b17f
DIFF: https://github.com/llvm/llvm-project/commit/a6fe3c7422db83346c336346e0b7a56ff084b17f.diff

LOG: [libc++][test] Migrate _BitInt probe to __BITINT_MAXWIDTH__ and fix latent test bugs (#203876)

`libcxx` tests gate `_BitInt` blocks on `TEST_HAS_EXTENSION(bit_int)`,
which is not a recognized Clang extension and returns 0 in every
language mode. The blocks have been compiling as dead code, hiding
latent bugs across 23 files.

Migrate to a `TEST_HAS_BITINT` helper backed by the standard
`__BITINT_MAXWIDTH__`. The latent bugs the activation surfaces are fixed
in the same commit:
- overflow-safe `min`;
- post-P4052R0 saturating-arithmetic renames plus a
`clang-21`/`apple-clang-21` skip for `saturating.bitint.pass.cpp` (Clang
21 asserts in constexpr eval on non-byte-aligned `_BitInt`);
- an `intcmp` syntax fix;
- `byteswap.verify` directive tightening;
- a missing `<climits>` include in `byteswap.pass` (only visible under
`-fmodules`);
- C++03-compatible `static_assert` form in `digits10`; gating
`digits`/`digits10` `_BitInt` blocks behind
`!_LIBCPP_USE_FROZEN_CXX03_HEADERS` since the fix from #193002 was not
backported to the frozen snapshot; and
- `make_format_args` reduced to a placeholder pending a SFINAE-friendly
rejection path.

Discussion:
https://discourse.llvm.org/t/implementing-p3666r4-bit-precise-integers-in-libc/91070

Assisted-by: Claude (Anthropic)

---------

Co-authored-by: Claude Opus 4.6 <noreply at anthropic.com>

Added: 
    

Modified: 
    libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp
    libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp
    libcxx/test/std/containers/views/mdspan/extents/bitint.pass.cpp
    libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp
    libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp
    libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp
    libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp
    libcxx/test/std/numerics/bit/bit.pow.two/bit_ceil.pass.cpp
    libcxx/test/std/numerics/bit/bit.pow.two/bit_floor.pass.cpp
    libcxx/test/std/numerics/bit/bit.pow.two/bit_width.pass.cpp
    libcxx/test/std/numerics/bit/bit.pow.two/has_single_bit.pass.cpp
    libcxx/test/std/numerics/bit/bitops.count/countl_one.pass.cpp
    libcxx/test/std/numerics/bit/bitops.count/countl_zero.pass.cpp
    libcxx/test/std/numerics/bit/bitops.count/countr_one.pass.cpp
    libcxx/test/std/numerics/bit/bitops.count/countr_zero.pass.cpp
    libcxx/test/std/numerics/bit/bitops.count/popcount.pass.cpp
    libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
    libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
    libcxx/test/std/numerics/bit/byteswap.pass.cpp
    libcxx/test/std/numerics/bit/byteswap.verify.cpp
    libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating.bitint.pass.cpp
    libcxx/test/std/utilities/utility/utility.intcmp/intcmp.bitint.pass.cpp
    libcxx/test/support/test_macros.h

Removed: 
    libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.bitint.verify.cpp


################################################################################
diff  --git a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp
index 1f2d9685bbe5a..524b22cc4bef3 100644
--- a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp
+++ b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_signed_integer.compile.pass.cpp
@@ -79,7 +79,7 @@ static_assert(!std::__signed_integer<int&>);
 static_assert(!std::__signed_integer<const int&>);
 
 // Extended signed integer types per [basic.fundamental]/p3 Note 1.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
 static_assert(std::__signed_integer<signed _BitInt(8)>);
 static_assert(std::__signed_integer<signed _BitInt(16)>);
 static_assert(std::__signed_integer<signed _BitInt(64)>);

diff  --git a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp
index 3f78f170b7038..234cc56f1697d 100644
--- a/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp
+++ b/libcxx/test/libcxx/concepts/concepts.arithmetic/__libcpp_unsigned_integer.compile.pass.cpp
@@ -79,7 +79,7 @@ static_assert(!std::__unsigned_integer<unsigned int&>);
 static_assert(!std::__unsigned_integer<const unsigned int&>);
 
 // Extended unsigned integer types per [basic.fundamental]/p3 Note 1.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
 static_assert(std::__unsigned_integer<unsigned _BitInt(8)>);
 static_assert(std::__unsigned_integer<unsigned _BitInt(16)>);
 static_assert(std::__unsigned_integer<unsigned _BitInt(64)>);

diff  --git a/libcxx/test/std/containers/views/mdspan/extents/bitint.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/bitint.pass.cpp
index 9a4dc02a15c6e..1f03730f7cb30 100644
--- a/libcxx/test/std/containers/views/mdspan/extents/bitint.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/extents/bitint.pass.cpp
@@ -27,7 +27,7 @@
 
 #include "test_macros.h"
 
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
 
 template <class IndexType>
 constexpr bool test_extents_with_index_type() {
@@ -72,10 +72,10 @@ constexpr bool test() {
   return true;
 }
 
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
 int main(int, char**) {
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
   test();
   static_assert(test());
 #endif

diff  --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp
index 807ea69f07680..0522c9b3af330 100644
--- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp
@@ -10,6 +10,8 @@
 
 // digits
 
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
 #include <limits>
 #include <cfloat>
 
@@ -55,7 +57,7 @@ int main(int, char**)
 
     // _BitInt(N): digits must equal N for unsigned and N-1 for signed,
     // regardless of padding bits for non-byte-aligned widths.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     // Byte-aligned widths.
     test<unsigned _BitInt(8), 8>();
     test<signed _BitInt(8), 7>();
@@ -89,7 +91,7 @@ int main(int, char**)
     test<unsigned _BitInt(4096), 4096>();
     test<signed _BitInt(4096), 4095>();
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp
index 002f951b2b829..3df9dc26dc94d 100644
--- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp
@@ -10,6 +10,8 @@
 
 // digits10
 
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
 #include <limits>
 #include <cfloat>
 
@@ -58,7 +60,7 @@ int main(int, char**)
     test<long double, LDBL_DIG>();
 
     // _BitInt(N): digits10 = floor((N - is_signed) * log10(2)).
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     test<unsigned _BitInt(8), 2>();   // digits=8,   log10=2.4
     test<signed _BitInt(8), 2>();     // digits=7,   log10=2.1
     test<unsigned _BitInt(13), 3>();  // digits=13,  log10=3.9
@@ -107,8 +109,8 @@ int main(int, char**)
     // The 1936274/6432163 convergent stays exact up to d=51132156. 8388608 is
     // the largest width tested above, so if Clang raises __BITINT_MAXWIDTH__,
     // extend the coverage before trusting the formula at the new range.
-    LIBCPP_STATIC_ASSERT(__BITINT_MAXWIDTH__ <= 8388608);
-#endif // TEST_HAS_EXTENSION(bit_int)
+    LIBCPP_STATIC_ASSERT(__BITINT_MAXWIDTH__ <= 8388608, "extend digits10 _BitInt coverage for the new maximum width");
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp
index fe8f039416d3a..06355c9de4771 100644
--- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp
@@ -67,16 +67,25 @@ int main(int, char**)
 
     // _BitInt(N): max is 2^N - 1 for unsigned and 2^(N-1) - 1 for signed.
     // Exercises the digits fix through `__max = ~0 ^ __min`.
-#if TEST_HAS_EXTENSION(bit_int)
+    // TODO: Remove guards for MSan once https://llvm.org/PR204217 is fixed.
+    // MSan does not track _BitInt padding bits, so non-byte-aligned widths
+    // surface as false-positive use-of-uninitialized-value through the
+    // numeric_limits::max() shift; restrict to byte-aligned widths under
+    // memory sanitizer.
+#if TEST_HAS_BITINT
     test<unsigned _BitInt(8)>((unsigned _BitInt(8)) ~(unsigned _BitInt(8))0);
     test<signed _BitInt(8)>((signed _BitInt(8))0x7F);
+#  if !TEST_HAS_FEATURE(memory_sanitizer)
     test<unsigned _BitInt(13)>((unsigned _BitInt(13))0x1FFF);
     test<signed _BitInt(13)>((signed _BitInt(13))0x0FFF);
+#  endif
     test<unsigned _BitInt(64)>((unsigned _BitInt(64)) ~(unsigned _BitInt(64))0);
     test<signed _BitInt(64)>((signed _BitInt(64))0x7FFFFFFFFFFFFFFFLL);
 #  if __BITINT_MAXWIDTH__ >= 128
+#    if !TEST_HAS_FEATURE(memory_sanitizer)
     test<unsigned _BitInt(77)>((unsigned _BitInt(77)) ~(unsigned _BitInt(77))0);
     test<signed _BitInt(77)>((signed _BitInt(77)) ~((signed _BitInt(77))1 << 76));
+#    endif
     test<unsigned _BitInt(128)>((unsigned _BitInt(128)) ~(unsigned _BitInt(128))0);
     test<signed _BitInt(128)>((signed _BitInt(128)) ~((signed _BitInt(128))1 << 127));
 #  endif

diff  --git a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp
index a9c72da2103b4..38a06cbed9e23 100644
--- a/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp
@@ -68,22 +68,33 @@ int main(int, char**)
     // _BitInt(N): min is 0 for unsigned and -2^(N-1) for signed. The shift
     // `1 << digits` flowed through the buggy digits field, so this also
     // exercises the digits fix for non-byte-aligned widths.
-#if TEST_HAS_EXTENSION(bit_int)
+    // TODO: Remove guards for MSan once https://llvm.org/PR204217 is fixed.
+    // MSan does not track _BitInt padding bits, so non-byte-aligned widths
+    // surface as false-positive use-of-uninitialized-value through the
+    // numeric_limits::min() shift; restrict to byte-aligned widths under
+    // memory sanitizer.
+#if TEST_HAS_BITINT
+    // signed _BitInt(N) min is -2^(N-1). Build via unsigned shift then cast to
+    // avoid integer-overflow warnings (-Werror,-Winteger-overflow).
     test<unsigned _BitInt(8)>(0);
-    test<signed _BitInt(8)>(-(signed _BitInt(8))(1 << 7));
+    test<signed _BitInt(8)>(static_cast<signed _BitInt(8)>(static_cast<unsigned _BitInt(8)>(1) << 7));
+#  if !TEST_HAS_FEATURE(memory_sanitizer)
     test<unsigned _BitInt(13)>(0);
-    test<signed _BitInt(13)>(-(signed _BitInt(13))(1 << 12));
+    test<signed _BitInt(13)>(static_cast<signed _BitInt(13)>(static_cast<unsigned _BitInt(13)>(1) << 12));
+#  endif
     test<unsigned _BitInt(64)>(0);
-    test<signed _BitInt(64)>(-(signed _BitInt(64))(1ULL << 63));
+    test<signed _BitInt(64)>(static_cast<signed _BitInt(64)>(static_cast<unsigned _BitInt(64)>(1) << 63));
 #  if __BITINT_MAXWIDTH__ >= 128
+#    if !TEST_HAS_FEATURE(memory_sanitizer)
     test<unsigned _BitInt(77)>(0);
-    test<signed _BitInt(77)>(-((signed _BitInt(77))1 << 76));
+    test<signed _BitInt(77)>(static_cast<signed _BitInt(77)>(static_cast<unsigned _BitInt(77)>(1) << 76));
+#    endif
     test<unsigned _BitInt(128)>(0);
-    test<signed _BitInt(128)>(-((signed _BitInt(128))1 << 127));
+    test<signed _BitInt(128)>(static_cast<signed _BitInt(128)>(static_cast<unsigned _BitInt(128)>(1) << 127));
 #  endif
 #  if __BITINT_MAXWIDTH__ >= 256
     test<unsigned _BitInt(256)>(0);
-    test<signed _BitInt(256)>(-((signed _BitInt(256))1 << 255));
+    test<signed _BitInt(256)>(static_cast<signed _BitInt(256)>(static_cast<unsigned _BitInt(256)>(1) << 255));
 #  endif
 #endif
 

diff  --git a/libcxx/test/std/numerics/bit/bit.pow.two/bit_ceil.pass.cpp b/libcxx/test/std/numerics/bit/bit.pow.two/bit_ceil.pass.cpp
index 1aaddafe40cc7..092f08dbb22e7 100644
--- a/libcxx/test/std/numerics/bit/bit.pow.two/bit_ceil.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bit.pow.two/bit_ceil.pass.cpp
@@ -142,7 +142,7 @@ int main(int, char**)
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
     // bit_ceil uses numeric_limits::digits, so only byte-aligned widths.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T32 = unsigned _BitInt(32);
       using T64 = unsigned _BitInt(64);
@@ -200,7 +200,7 @@ int main(int, char**)
       assert(std::bit_ceil((T256(1) << 200) + 1) == T256(1) << 201);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bit.pow.two/bit_floor.pass.cpp b/libcxx/test/std/numerics/bit/bit.pow.two/bit_floor.pass.cpp
index 07dae010b99fa..a233565838e87 100644
--- a/libcxx/test/std/numerics/bit/bit.pow.two/bit_floor.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bit.pow.two/bit_floor.pass.cpp
@@ -142,7 +142,7 @@ int main(int, char**)
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
     // bit_floor uses numeric_limits::digits via __bit_log2, so only
     // byte-aligned widths are safe.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T32 = unsigned _BitInt(32);
       using T64 = unsigned _BitInt(64);
@@ -200,7 +200,7 @@ int main(int, char**)
       assert(std::bit_floor(T256(~T256(0))) == T256(T256(1) << 255));
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bit.pow.two/bit_width.pass.cpp b/libcxx/test/std/numerics/bit/bit.pow.two/bit_width.pass.cpp
index efba0dcd2b77b..e160741de90a7 100644
--- a/libcxx/test/std/numerics/bit/bit.pow.two/bit_width.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bit.pow.two/bit_width.pass.cpp
@@ -145,7 +145,7 @@ int main(int, char**)
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
     // bit_width uses numeric_limits::digits via __bit_log2, so only
     // byte-aligned widths are safe.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T32 = unsigned _BitInt(32);
       using T64 = unsigned _BitInt(64);
@@ -196,7 +196,7 @@ int main(int, char**)
       assert(std::bit_width(T256(~T256(0))) == 256);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bit.pow.two/has_single_bit.pass.cpp b/libcxx/test/std/numerics/bit/bit.pow.two/has_single_bit.pass.cpp
index 6bab2b9f9069a..d1c75e0e53b93 100644
--- a/libcxx/test/std/numerics/bit/bit.pow.two/has_single_bit.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bit.pow.two/has_single_bit.pass.cpp
@@ -141,7 +141,7 @@ int main(int, char**)
     test<std::size_t>();
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T13 = unsigned _BitInt(13);
       using T32 = unsigned _BitInt(32);
@@ -225,7 +225,7 @@ int main(int, char**)
       assert(!std::has_single_bit((T4096(1) << 4095) | T4096(1)));
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.count/countl_one.pass.cpp b/libcxx/test/std/numerics/bit/bitops.count/countl_one.pass.cpp
index 39d5db1ed22a8..f176eeb2c21af 100644
--- a/libcxx/test/std/numerics/bit/bitops.count/countl_one.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.count/countl_one.pass.cpp
@@ -138,7 +138,7 @@ int main(int, char**)
     test<std::size_t>();
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T13 = unsigned _BitInt(13);
       using T32 = unsigned _BitInt(32);
@@ -198,7 +198,7 @@ int main(int, char**)
       assert(std::countl_one(T4096(~T4096(0) ^ (T4096(1) << 1000))) == 3095);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.count/countl_zero.pass.cpp b/libcxx/test/std/numerics/bit/bitops.count/countl_zero.pass.cpp
index a73175d51a201..af1c3517b45e7 100644
--- a/libcxx/test/std/numerics/bit/bitops.count/countl_zero.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.count/countl_zero.pass.cpp
@@ -137,7 +137,7 @@ int main(int, char**)
     test<std::size_t>();
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T8  = unsigned _BitInt(8);
       using T13 = unsigned _BitInt(13);
@@ -219,7 +219,7 @@ int main(int, char**)
       assert(std::countl_zero(T4096(~T4096(0))) == 0);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.count/countr_one.pass.cpp b/libcxx/test/std/numerics/bit/bitops.count/countr_one.pass.cpp
index ba350a76d96af..64e1506f49e85 100644
--- a/libcxx/test/std/numerics/bit/bitops.count/countr_one.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.count/countr_one.pass.cpp
@@ -142,7 +142,7 @@ int main(int, char**)
     test<std::size_t>();
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T13 = unsigned _BitInt(13);
       using T32 = unsigned _BitInt(32);
@@ -215,7 +215,7 @@ int main(int, char**)
       assert(std::countr_one(T4096((T4096(1) << 1000) - 1)) == 1000);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.count/countr_zero.pass.cpp b/libcxx/test/std/numerics/bit/bitops.count/countr_zero.pass.cpp
index e7e9d6542ab86..87b9e67e2a03b 100644
--- a/libcxx/test/std/numerics/bit/bitops.count/countr_zero.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.count/countr_zero.pass.cpp
@@ -139,7 +139,7 @@ int main(int, char**)
     test<std::size_t>();
 
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T8  = unsigned _BitInt(8);
       using T13 = unsigned _BitInt(13);
@@ -210,7 +210,7 @@ int main(int, char**)
       assert(std::countr_zero(T4096(1) << 4095) == 4095);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.count/popcount.pass.cpp b/libcxx/test/std/numerics/bit/bitops.count/popcount.pass.cpp
index dc5cdf89f147b..a06a8ca958bf7 100644
--- a/libcxx/test/std/numerics/bit/bitops.count/popcount.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.count/popcount.pass.cpp
@@ -151,7 +151,7 @@ int main(int, char**)
     // _BitInt tests. Width tiers follow C23 7.18.2.5: BITINT_MAXWIDTH is
     // guaranteed to be >= ULLONG_WIDTH (>= 64). Anything beyond that is
     // optional and must be guarded by __BITINT_MAXWIDTH__.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       // Guaranteed widths (<= 64 bits).
       using T8  = unsigned _BitInt(8);
@@ -255,7 +255,7 @@ int main(int, char**)
       assert(std::popcount(mask1000) == 1000);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp b/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
index e9859ac6398b3..da0941dc0929d 100644
--- a/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
@@ -168,7 +168,7 @@ int main(int, char**)
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
     // rotl uses numeric_limits::digits internally, so only byte-aligned
     // widths are safe (where digits matches the actual bit width).
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T32 = unsigned _BitInt(32);
       using T64 = unsigned _BitInt(64);
@@ -219,7 +219,7 @@ int main(int, char**)
       assert(std::rotl(T256(1), 256 + 4) == T256(1) << 4);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp b/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
index 428e11dba4969..bbcc1afe7864d 100644
--- a/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
@@ -168,7 +168,7 @@ int main(int, char**)
     // _BitInt tests. Width tiers follow C23 7.18.2.5.
     // rotr uses numeric_limits::digits internally, so only byte-aligned
     // widths are safe.
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
     {
       using T32 = unsigned _BitInt(32);
       using T64 = unsigned _BitInt(64);
@@ -219,7 +219,7 @@ int main(int, char**)
       assert(std::rotr(T256(1), 256 + 4) == T256(1) << 252);
     }
 #  endif
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
     return 0;
 }

diff  --git a/libcxx/test/std/numerics/bit/byteswap.pass.cpp b/libcxx/test/std/numerics/bit/byteswap.pass.cpp
index f96af9410ead3..0afdc6e8143ba 100644
--- a/libcxx/test/std/numerics/bit/byteswap.pass.cpp
+++ b/libcxx/test/std/numerics/bit/byteswap.pass.cpp
@@ -10,6 +10,7 @@
 
 #include <bit>
 #include <cassert>
+#include <climits>
 #include <cstddef>
 #include <cstdint>
 #include <utility>
@@ -98,7 +99,7 @@ constexpr bool test() {
   test_implementation_defined_size<long long>();
   test_implementation_defined_size<unsigned long long>();
 
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
   // _BitInt(N) where digits + is_signed == sizeof * CHAR_BIT (no padding
   // bits) is accepted; other widths are rejected by the static_assert
   // inside the function body (see byteswap.verify.cpp).
@@ -119,8 +120,12 @@ constexpr bool test() {
   test_num<unsigned _BitInt(64)>(0x0123456789ABCDEFULL, 0xEFCDAB8967452301ULL);
   test_num<signed _BitInt(64)>(0x0123456789ABCDEFLL, static_cast<signed _BitInt(64)>(0xEFCDAB8967452301ULL));
 
-#  if __BITINT_MAXWIDTH__ >= 128
-  // sizeof == 16: __builtin_bswap128 fallback or __builtin_bswapg.
+#  if __BITINT_MAXWIDTH__ >= 128 && (TEST_HAS_BUILTIN(__builtin_bswapg) || !defined(TEST_HAS_NO_INT128))
+  // sizeof == 16: __builtin_bswap128 fallback or __builtin_bswapg. Targets
+  // without libc++ __int128 (32-bit ARM, MSVC ABI on Windows clang-cl) and an
+  // older compiler that lacks __builtin_bswapg cannot byteswap a 16-byte
+  // value; skip the block. TEST_HAS_NO_INT128 mirrors libc++'s
+  // _LIBCPP_HAS_INT128 (false on _MSC_VER even when __SIZEOF_INT128__ is set).
   unsigned _BitInt(128) v128 =
       (static_cast<unsigned _BitInt(128)>(0x0123456789ABCDEFULL) << 64) |
       static_cast<unsigned _BitInt(128)>(0x13579BDF02468ACEULL);
@@ -131,7 +136,7 @@ constexpr bool test() {
   test_num<signed _BitInt(128)>(static_cast<signed _BitInt(128)>(v128), static_cast<signed _BitInt(128)>(v128_swapped));
 #  endif
 
-#  if __has_builtin(__builtin_bswapg) && __BITINT_MAXWIDTH__ >= 256
+#  if TEST_HAS_BUILTIN(__builtin_bswapg) && __BITINT_MAXWIDTH__ >= 256
   // sizeof > 16: only the __builtin_bswapg path supports widths beyond what
   // __builtin_bswap16/32/64/128 cover.
   unsigned _BitInt(256) v256 =

diff  --git a/libcxx/test/std/numerics/bit/byteswap.verify.cpp b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
index f7ff1c6aefb11..5a205d9ec5051 100644
--- a/libcxx/test/std/numerics/bit/byteswap.verify.cpp
+++ b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
@@ -18,51 +18,55 @@
 
 #include "test_macros.h"
 
-#if TEST_HAS_EXTENSION(bit_int)
-
-// Sub-byte widths (sizeof == 1 but bit width below CHAR_BIT)
-void test_unsigned_1() {
-  unsigned _BitInt(1) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
-  (void)std::byteswap(v);
-}
+#if TEST_HAS_BITINT
 
+// Sub-byte widths (sizeof == 1 but bit width below CHAR_BIT).
+// _BitInt(1) is excluded because make_unsigned on _BitInt(1) triggers a
+// separate static_assert that's unrelated to byteswap's padding-bit Mandate.
 void test_unsigned_7() {
   unsigned _BitInt(7) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 void test_signed_7() {
   signed _BitInt(7) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 // Non-byte-aligned widths
 void test_unsigned_13() {
   unsigned _BitInt(13) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 void test_unsigned_17() {
   unsigned _BitInt(17) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 void test_signed_33() {
   signed _BitInt(33) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
+// Widths with sizeof == 16 land on the libc++ 128-bit dispatch path, which is
+// gated on _LIBCPP_HAS_INT128 or __builtin_bswapg. On platforms without
+// either, the size-dispatch static_assert fires alongside the padding-bit
+// one, doubling the diagnostic count and breaking 1-to-1 directive matching.
+// Restrict 65/80/96/112 to platforms that have one path. TEST_HAS_NO_INT128
+// mirrors libc++'s _LIBCPP_HAS_INT128 (also false on _MSC_VER).
+#  if TEST_HAS_BUILTIN(__builtin_bswapg) || !defined(TEST_HAS_NO_INT128)
 void test_unsigned_65() {
   unsigned _BitInt(65) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
+#  endif
 
 // Byte-aligned widths whose value bits don't fill the object representation.
 // On platforms where sizeof(_BitInt(N)) rounds up to a power of two, these
@@ -71,14 +75,14 @@ void test_unsigned_65() {
 void test_unsigned_24() {
   // sizeof(_BitInt(24)) == 4 on x86_64; 8 padding bits.
   unsigned _BitInt(24) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 void test_unsigned_40() {
   // sizeof(_BitInt(40)) == 8 on x86_64; 24 padding bits.
   unsigned _BitInt(40) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
@@ -87,54 +91,51 @@ void test_unsigned_48() {
   // bit width (48) is a multiple of 16, so __builtin_bswapg accepts it -- the
   // libc++ static_assert is what actually catches this case.
   unsigned _BitInt(48) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
 void test_unsigned_56() {
   // sizeof(_BitInt(56)) == 8 on x86_64; 8 padding bits.
   unsigned _BitInt(56) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
 
-#  if __BITINT_MAXWIDTH__ >= 80
+// Same dispatch-availability guard as test_unsigned_65 above.
+#  if TEST_HAS_BUILTIN(__builtin_bswapg) || !defined(TEST_HAS_NO_INT128)
+#    if __BITINT_MAXWIDTH__ >= 80
 void test_unsigned_80() {
   // sizeof(_BitInt(80)) == 16 on x86_64; 48 padding bits. Width 80 is also
   // a multiple of 16, so bswapg would accept it without the static_assert.
   unsigned _BitInt(80) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
-#  endif
+#    endif
 
-#  if __BITINT_MAXWIDTH__ >= 96
+#    if __BITINT_MAXWIDTH__ >= 96
 void test_unsigned_96() {
   // sizeof(_BitInt(96)) == 16 on x86_64; 32 padding bits.
   unsigned _BitInt(96) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
-#  endif
+#    endif
 
-#  if __BITINT_MAXWIDTH__ >= 112
+#    if __BITINT_MAXWIDTH__ >= 112
 void test_unsigned_112() {
   // sizeof(_BitInt(112)) == 16 on x86_64; 16 padding bits.
   unsigned _BitInt(112) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
+  // expected-error-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
   (void)std::byteswap(v);
 }
+#    endif
 #  endif
 
-#  if __BITINT_MAXWIDTH__ >= 256
-void test_unsigned_192() {
-  // sizeof(_BitInt(192)) == 32 on x86_64; 64 padding bits. Multiple of 16
-  // but not of the storage size.
-  unsigned _BitInt(192) v = 0;
-  // expected-error@*:* {{static assertion failed{{.*}}std::byteswap requires T to have no padding bits}}
-  (void)std::byteswap(v);
-}
-#  endif
+// Widths above 128 bits drop out: Clang's sizeof for those widths matches the
+// value width on x86_64 (e.g., sizeof(_BitInt(192)) == 24), so there are no
+// padding bits to reject.
 
 #else
 // expected-no-diagnostics

diff  --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating.bitint.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating.bitint.pass.cpp
index a4c68b0d582ad..9f233c785cbf3 100644
--- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating.bitint.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating.bitint.pass.cpp
@@ -8,22 +8,18 @@
 
 // REQUIRES: std-at-least-c++26
 
+// TODO(LLVM25): Remove these restrictions.
+// Clang <= 22 mis-evaluates std::saturating_mul on non-byte-aligned _BitInt at
+// compile time. See https://llvm.org/PR204085 (fixed in Clang 23 via
+// https://llvm.org/PR192568). The latest version of Android Clang still has
+// this bug.
+// UNSUPPORTED: clang-19, clang-20, clang-21, clang-22
+// UNSUPPORTED: apple-clang-17, apple-clang-18, apple-clang-19, apple-clang-20, apple-clang-21
+// UNSUPPORTED: target={{.+}}-android{{.*}}
+
 // <numeric>
 
-// add_sat, sub_sat, mul_sat, div_sat, saturate_cast applied to _BitInt(N).
-//
-// After [libc++] recognized _BitInt as an integer type in
-// __type_traits/integer_traits.h, these functions silently started
-// accepting _BitInt arguments. Saturation at min/max depends on
-// numeric_limits<_BitInt(N)>::min/max being correct, which requires the
-// digits10 fix from #193002 for odd widths.
-//
-// Widths covered:
-//   -  _BitInt(13):  odd narrow width, signed range -4096..4095.
-//                    Exercises fixed digits10 for saturation clamp.
-//   -  _BitInt(64):  equal to long long, integer_traits boundary.
-//   -  _BitInt(128): matches __int128 on targets that support it.
-//   -  _BitInt(200): beyond __int128 (optional via __BITINT_MAXWIDTH__).
+// std::saturating_{add,sub,mul,div,cast} applied to _BitInt(N).
 
 #include <cassert>
 #include <limits>
@@ -31,7 +27,7 @@
 
 #include "test_macros.h"
 
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
 
 template <class T>
 constexpr bool test_signed_add_sub() {
@@ -39,28 +35,28 @@ constexpr bool test_signed_add_sub() {
   constexpr T max_v = std::numeric_limits<T>::max();
 
   // Basic: no overflow.
-  assert(std::add_sat(T(1), T(2)) == T(3));
-  assert(std::add_sat(T(-1), T(1)) == T(0));
-  assert(std::sub_sat(T(5), T(3)) == T(2));
-  assert(std::sub_sat(T(-1), T(-1)) == T(0));
+  assert(std::saturating_add(T(1), T(2)) == T(3));
+  assert(std::saturating_add(T(-1), T(1)) == T(0));
+  assert(std::saturating_sub(T(5), T(3)) == T(2));
+  assert(std::saturating_sub(T(-1), T(-1)) == T(0));
 
   // Positive overflow clamps to max.
-  assert(std::add_sat(max_v, T(1)) == max_v);
-  assert(std::add_sat(T(1), max_v) == max_v);
-  assert(std::add_sat(max_v, max_v) == max_v);
+  assert(std::saturating_add(max_v, T(1)) == max_v);
+  assert(std::saturating_add(T(1), max_v) == max_v);
+  assert(std::saturating_add(max_v, max_v) == max_v);
 
   // Negative overflow clamps to min.
-  assert(std::add_sat(min_v, T(-1)) == min_v);
-  assert(std::add_sat(T(-1), min_v) == min_v);
-  assert(std::add_sat(min_v, min_v) == min_v);
+  assert(std::saturating_add(min_v, T(-1)) == min_v);
+  assert(std::saturating_add(T(-1), min_v) == min_v);
+  assert(std::saturating_add(min_v, min_v) == min_v);
 
-  // sub_sat positive overflow (x >= 0, y < 0).
-  assert(std::sub_sat(max_v, T(-1)) == max_v);
-  assert(std::sub_sat(max_v, min_v) == max_v);
+  // saturating_sub positive overflow (x >= 0, y < 0).
+  assert(std::saturating_sub(max_v, T(-1)) == max_v);
+  assert(std::saturating_sub(max_v, min_v) == max_v);
 
-  // sub_sat negative overflow (x < 0, y > 0).
-  assert(std::sub_sat(min_v, T(1)) == min_v);
-  assert(std::sub_sat(min_v, max_v) == min_v);
+  // saturating_sub negative overflow (x < 0, y > 0).
+  assert(std::saturating_sub(min_v, T(1)) == min_v);
+  assert(std::saturating_sub(min_v, max_v) == min_v);
 
   return true;
 }
@@ -70,18 +66,18 @@ constexpr bool test_unsigned_add_sub() {
   constexpr T max_v = std::numeric_limits<T>::max();
 
   // Basic.
-  assert(std::add_sat(T(1), T(2)) == T(3));
-  assert(std::sub_sat(T(5), T(3)) == T(2));
+  assert(std::saturating_add(T(1), T(2)) == T(3));
+  assert(std::saturating_sub(T(5), T(3)) == T(2));
 
   // Upper clamp.
-  assert(std::add_sat(max_v, T(1)) == max_v);
-  assert(std::add_sat(T(1), max_v) == max_v);
-  assert(std::add_sat(max_v, max_v) == max_v);
+  assert(std::saturating_add(max_v, T(1)) == max_v);
+  assert(std::saturating_add(T(1), max_v) == max_v);
+  assert(std::saturating_add(max_v, max_v) == max_v);
 
   // Lower clamp (wrap-to-zero on unsigned).
-  assert(std::sub_sat(T(0), T(1)) == T(0));
-  assert(std::sub_sat(T(0), max_v) == T(0));
-  assert(std::sub_sat(T(3), T(5)) == T(0));
+  assert(std::saturating_sub(T(0), T(1)) == T(0));
+  assert(std::saturating_sub(T(0), max_v) == T(0));
+  assert(std::saturating_sub(T(3), T(5)) == T(0));
 
   return true;
 }
@@ -92,25 +88,25 @@ constexpr bool test_signed_mul_div() {
   constexpr T max_v = std::numeric_limits<T>::max();
 
   // Basic mul.
-  assert(std::mul_sat(T(2), T(3)) == T(6));
-  assert(std::mul_sat(T(-2), T(3)) == T(-6));
+  assert(std::saturating_mul(T(2), T(3)) == T(6));
+  assert(std::saturating_mul(T(-2), T(3)) == T(-6));
 
   // Overflow to max.
-  assert(std::mul_sat(max_v, T(2)) == max_v);
-  assert(std::mul_sat(T(-1), min_v) == max_v); // -(-min) overflows to +max
-  assert(std::mul_sat(min_v, T(-1)) == max_v);
+  assert(std::saturating_mul(max_v, T(2)) == max_v);
+  assert(std::saturating_mul(T(-1), min_v) == max_v); // -(-min) overflows to +max
+  assert(std::saturating_mul(min_v, T(-1)) == max_v);
 
   // Overflow to min.
-  assert(std::mul_sat(max_v, T(-2)) == min_v);
-  assert(std::mul_sat(T(-2), max_v) == min_v);
+  assert(std::saturating_mul(max_v, T(-2)) == min_v);
+  assert(std::saturating_mul(T(-2), max_v) == min_v);
 
-  // div_sat: regular values.
-  assert(std::div_sat(T(6), T(3)) == T(2));
-  assert(std::div_sat(T(7), T(3)) == T(2));
-  assert(std::div_sat(T(-6), T(3)) == T(-2));
+  // saturating_div: regular values.
+  assert(std::saturating_div(T(6), T(3)) == T(2));
+  assert(std::saturating_div(T(7), T(3)) == T(2));
+  assert(std::saturating_div(T(-6), T(3)) == T(-2));
 
   // The one signed division overflow case: INT_MIN / -1.
-  assert(std::div_sat(min_v, T(-1)) == max_v);
+  assert(std::saturating_div(min_v, T(-1)) == max_v);
 
   return true;
 }
@@ -119,13 +115,13 @@ template <class T>
 constexpr bool test_unsigned_mul_div() {
   constexpr T max_v = std::numeric_limits<T>::max();
 
-  assert(std::mul_sat(T(2), T(3)) == T(6));
-  assert(std::mul_sat(max_v, T(2)) == max_v); // clamp
-  assert(std::mul_sat(T(0), max_v) == T(0));
-  assert(std::mul_sat(max_v, max_v) == max_v);
+  assert(std::saturating_mul(T(2), T(3)) == T(6));
+  assert(std::saturating_mul(max_v, T(2)) == max_v); // clamp
+  assert(std::saturating_mul(T(0), max_v) == T(0));
+  assert(std::saturating_mul(max_v, max_v) == max_v);
 
-  assert(std::div_sat(T(10), T(3)) == T(3));
-  assert(std::div_sat(max_v, T(1)) == max_v);
+  assert(std::saturating_div(T(10), T(3)) == T(3));
+  assert(std::saturating_div(max_v, T(1)) == max_v);
   return true;
 }
 
@@ -136,19 +132,19 @@ constexpr bool test_saturate_cast() {
   constexpr U u_max = std::numeric_limits<U>::max();
 
   // Same-type: no clamp.
-  assert(std::saturate_cast<S>(S(0)) == S(0));
-  assert(std::saturate_cast<S>(s_max) == s_max);
-  assert(std::saturate_cast<S>(s_min) == s_min);
-  assert(std::saturate_cast<U>(U(0)) == U(0));
-  assert(std::saturate_cast<U>(u_max) == u_max);
+  assert(std::saturating_cast<S>(S(0)) == S(0));
+  assert(std::saturating_cast<S>(s_max) == s_max);
+  assert(std::saturating_cast<S>(s_min) == s_min);
+  assert(std::saturating_cast<U>(U(0)) == U(0));
+  assert(std::saturating_cast<U>(u_max) == u_max);
 
   // Signed -> unsigned: negative clamps to zero.
-  assert(std::saturate_cast<U>(S(-1)) == U(0));
-  assert(std::saturate_cast<U>(s_min) == U(0));
-  assert(std::saturate_cast<U>(S(1)) == U(1));
+  assert(std::saturating_cast<U>(S(-1)) == U(0));
+  assert(std::saturating_cast<U>(s_min) == U(0));
+  assert(std::saturating_cast<U>(S(1)) == U(1));
 
   // Unsigned -> signed: overflow clamps to s_max.
-  assert(std::saturate_cast<S>(u_max) == s_max);
+  assert(std::saturating_cast<S>(u_max) == s_max);
 
   return true;
 }
@@ -167,7 +163,7 @@ constexpr bool test() {
   test_unsigned_mul_div<unsigned _BitInt(64)>();
   test_saturate_cast<_BitInt(64), unsigned _BitInt(64)>();
 
-  // Cross-width saturate_cast: wide source clamped into narrow target.
+  // Cross-width saturating_cast: wide source clamped into narrow target.
   {
     using S13 = _BitInt(13);
     using S64 = _BitInt(64);
@@ -175,16 +171,16 @@ constexpr bool test() {
     using U64 = unsigned _BitInt(64);
 
     // wide signed -> narrow signed
-    assert(std::saturate_cast<S13>(std::numeric_limits<S64>::max()) == std::numeric_limits<S13>::max());
-    assert(std::saturate_cast<S13>(std::numeric_limits<S64>::min()) == std::numeric_limits<S13>::min());
+    assert(std::saturating_cast<S13>(std::numeric_limits<S64>::max()) == std::numeric_limits<S13>::max());
+    assert(std::saturating_cast<S13>(std::numeric_limits<S64>::min()) == std::numeric_limits<S13>::min());
     // wide unsigned -> narrow signed
-    assert(std::saturate_cast<S13>(std::numeric_limits<U64>::max()) == std::numeric_limits<S13>::max());
+    assert(std::saturating_cast<S13>(std::numeric_limits<U64>::max()) == std::numeric_limits<S13>::max());
     // wide signed -> narrow unsigned
-    assert(std::saturate_cast<U13>(std::numeric_limits<S64>::min()) == U13{0});
-    assert(std::saturate_cast<U13>(std::numeric_limits<S64>::max()) == std::numeric_limits<U13>::max());
+    assert(std::saturating_cast<U13>(std::numeric_limits<S64>::min()) == U13{0});
+    assert(std::saturating_cast<U13>(std::numeric_limits<S64>::max()) == std::numeric_limits<U13>::max());
     // exact-fit no clamp
-    assert(std::saturate_cast<S64>(S13{-1}) == S64{-1});
-    assert(std::saturate_cast<U64>(U13{42}) == U64{42});
+    assert(std::saturating_cast<S64>(S13{-1}) == S64{-1});
+    assert(std::saturating_cast<U64>(U13{42}) == U64{42});
   }
 
 #  if __BITINT_MAXWIDTH__ >= 128
@@ -195,31 +191,17 @@ constexpr bool test() {
   test_saturate_cast<_BitInt(128), unsigned _BitInt(128)>();
 #  endif
 
-#  if __BITINT_MAXWIDTH__ >= 200
-  // Beyond __int128: exercises the overflow-detection fallback on widths
-  // with no builtin add/sub/mul_sat mapping.
-  test_signed_add_sub<_BitInt(200)>();
-  test_unsigned_add_sub<unsigned _BitInt(200)>();
-  test_signed_mul_div<_BitInt(200)>();
-  test_unsigned_mul_div<unsigned _BitInt(200)>();
-  test_saturate_cast<_BitInt(200), unsigned _BitInt(200)>();
-
-  // Cross-width between 128- and 200-bit widths.
-  {
-    using S200 = _BitInt(200);
-    using S128 = _BitInt(128);
-    assert(std::saturate_cast<S128>(std::numeric_limits<S200>::max()) == std::numeric_limits<S128>::max());
-    assert(std::saturate_cast<S128>(std::numeric_limits<S200>::min()) == std::numeric_limits<S128>::min());
-  }
-#  endif
+  // TODO: __builtin_mul_overflow is currently broken for (unsigned) _BitInt(N)
+  // where N > 128 (https://llvm.org/PR46337). Cover them once this bug gets
+  // fixed.
 
   return true;
 }
 
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
 int main(int, char**) {
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
   test();
   static_assert(test());
 #endif

diff  --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.bitint.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.bitint.verify.cpp
deleted file mode 100644
index 52107b8b91527..0000000000000
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.bitint.verify.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// <format>
-
-// make_format_args with _BitInt(N) wider than __int128 is unsupported.
-//
-// After [libc++] recognized _BitInt as an integer type in
-// __type_traits/integer_traits.h, format_arg_store's __determine_arg_t
-// dispatches on sizeof(_Tp) and maps _BitInt up to sizeof(__int128) onto
-// the i128 storage slot. For wider _BitInt (sizeof > sizeof(__int128)),
-// no storage slot exists and a static_assert fires.
-//
-// This test pins down that diagnostic so that if the dispatch ever changes
-// to silently accept a wider type (or drops the diagnostic), the test
-// breaks and forces a reconsideration.
-
-#include <format>
-
-#include "test_macros.h"
-
-#if TEST_HAS_EXTENSION(bit_int) && __BITINT_MAXWIDTH__ >= 129
-
-void f_signed() {
-  // _BitInt(129) has sizeof == 32 on x86-64 (first size wider than __int128).
-  _BitInt(129) value = 0;
-  // expected-error-re@*:* {{{{(static assertion|static_assert)}} failed{{.*}}"an unsupported signed integer was used"}}
-  (void)std::make_format_args(value);
-}
-
-void f_unsigned() {
-  unsigned _BitInt(129) value = 0;
-  // expected-error-re@*:* {{{{(static assertion|static_assert)}} failed{{.*}}"an unsupported unsigned integer was used"}}
-  (void)std::make_format_args(value);
-}
-
-#  if __BITINT_MAXWIDTH__ >= 256
-void f_signed_256() {
-  _BitInt(256) value = 0;
-  // expected-error-re@*:* {{{{(static assertion|static_assert)}} failed{{.*}}"an unsupported signed integer was used"}}
-  (void)std::make_format_args(value);
-}
-#  endif
-
-#else
-// When _BitInt is unavailable or the implementation limits preclude the
-// test, keep the file well-formed with a trivial positive expectation so
-// the driver does not fail.
-// expected-no-diagnostics
-#endif

diff  --git a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.bitint.pass.cpp b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.bitint.pass.cpp
index f96ac1c9f7a32..4eb803734ead3 100644
--- a/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.bitint.pass.cpp
+++ b/libcxx/test/std/utilities/utility/utility.intcmp/intcmp.bitint.pass.cpp
@@ -36,7 +36,7 @@
 
 #include "test_macros.h"
 
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
 
 template <class T, class U>
 constexpr bool test_same_sign() {
@@ -157,15 +157,15 @@ constexpr bool test() {
   // Cross-type round-trip equality.
   static_assert(std::cmp_equal(_BitInt(13)(42), 42));
   static_assert(std::cmp_equal(42, _BitInt(13)(42)));
-  static_assert(std::cmp_equal(unsigned _BitInt(13)(42), 42u));
+  static_assert(std::cmp_equal(static_cast<unsigned _BitInt(13)>(42), 42u));
 
   return true;
 }
 
-#endif // TEST_HAS_EXTENSION(bit_int)
+#endif // TEST_HAS_BITINT
 
 int main(int, char**) {
-#if TEST_HAS_EXTENSION(bit_int)
+#if TEST_HAS_BITINT
   test();
   static_assert(test());
 #endif

diff  --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index 8d88d6fad7d0b..78b1f6eda6576 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -42,6 +42,15 @@
 #define TEST_HAS_EXTENSION(X) 0
 #endif
 
+// _BitInt(N) is a C23 standard feature and a Clang extension in earlier C and C++.
+// __BITINT_MAXWIDTH__ is the portable probe: defined by every compiler that accepts _BitInt.
+// Note __has_extension(bit_int) is unusable because it is not recognized by Clang and produces 0.
+#ifdef __BITINT_MAXWIDTH__
+#  define TEST_HAS_BITINT 1
+#else
+#  define TEST_HAS_BITINT 0
+#endif
+
 #ifdef __has_warning
 #define TEST_HAS_WARNING(X) __has_warning(X)
 #else


        


More information about the libcxx-commits mailing list