[libcxx-commits] [libcxx] [libc++][test] Drop _BitInt(96) byteswap padding check on 32-bit x86 (PR #205295)

Xavier Roche via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jun 27 04:00:53 PDT 2026


https://github.com/xroche updated https://github.com/llvm/llvm-project/pull/205295

>From 4ae67649d4e8107f68f160a085028d714f814eb7 Mon Sep 17 00:00:00 2001
From: Xavier Roche <xavier.roche at algolia.com>
Date: Tue, 23 Jun 2026 10:39:19 +0200
Subject: [PATCH 1/2] [libc++][test] Drop _BitInt(96) byteswap padding check on
 32-bit x86

byteswap.verify.cpp expected std::byteswap(unsigned _BitInt(96)) to be
rejected for having padding bits. That holds on x86_64, where the type
is 16 bytes (32 padding bits), but not on 32-bit x86: there _BitInt(96)
is 12 bytes with no padding, so byteswap is well-formed and the expected
diagnostic never fires. The Android i386 builder caught this.

Remove the width-96 case. Widths 80 and 112 still cover byte-aligned
padded types above 64 bits, and pad on both 32- and 64-bit targets.

Assisted-by: Claude (Anthropic)
Co-Authored-By: Claude Opus 4.6 <noreply at anthropic.com>
---
 .../test/std/numerics/bit/byteswap.verify.cpp   | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/libcxx/test/std/numerics/bit/byteswap.verify.cpp b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
index 5a205d9ec5051..f1614d11c9e0d 100644
--- a/libcxx/test/std/numerics/bit/byteswap.verify.cpp
+++ b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
@@ -68,10 +68,10 @@ void test_unsigned_65() {
 }
 #  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
-// types have padding bits in the high-order storage positions even though
-// their value width is a multiple of CHAR_BIT.
+// Byte-aligned widths whose value bits don't fill the object representation,
+// so the high-order storage holds padding bits. Only widths that pad on every
+// target are listed; 96 is omitted because _BitInt(96) is 12 bytes with no
+// padding on 32-bit x86.
 void test_unsigned_24() {
   // sizeof(_BitInt(24)) == 4 on x86_64; 8 padding bits.
   unsigned _BitInt(24) v = 0;
@@ -114,15 +114,6 @@ void test_unsigned_80() {
 }
 #    endif
 
-#    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-re@*:* {{{{(std::byteswap requires T to have no padding bits|byteswap is unimplemented for integral types of this size)}}}}
-  (void)std::byteswap(v);
-}
-#    endif
-
 #    if __BITINT_MAXWIDTH__ >= 112
 void test_unsigned_112() {
   // sizeof(_BitInt(112)) == 16 on x86_64; 16 padding bits.

>From f08a2a8d77c01e2a58ae7ce28a65e50e7e81a1a5 Mon Sep 17 00:00:00 2001
From: Xavier Roche <xavier.roche at algolia.com>
Date: Tue, 23 Jun 2026 11:07:34 +0200
Subject: [PATCH 2/2] [libc++][test] Gate _BitInt(96) byteswap case on
 !__i386__ instead of removing

Restore test_unsigned_96, dropped in the previous commit, behind
!defined(__i386__). The zero-padding behavior is specific to the i386
psABI, which aligns _BitInt to 4 bytes and packs _BitInt(96) into 12
bytes. Every other target, including 32-bit arm, riscv32, ppc32, mips32
and sparc32, gives it 16 bytes with 32 padding bits, so the case still
exercises the padding-bit Mandate everywhere except 32-bit x86.

sizeof is not available to the preprocessor, so the guard is a target
check rather than a direct has-padding predicate. Addresses review
feedback to gate the case rather than delete it.

Assisted-by: Claude (Anthropic)
Co-Authored-By: Claude Opus 4.6 <noreply at anthropic.com>
---
 .../test/std/numerics/bit/byteswap.verify.cpp   | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/numerics/bit/byteswap.verify.cpp b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
index f1614d11c9e0d..f9b6954f525da 100644
--- a/libcxx/test/std/numerics/bit/byteswap.verify.cpp
+++ b/libcxx/test/std/numerics/bit/byteswap.verify.cpp
@@ -69,9 +69,8 @@ void test_unsigned_65() {
 #  endif
 
 // Byte-aligned widths whose value bits don't fill the object representation,
-// so the high-order storage holds padding bits. Only widths that pad on every
-// target are listed; 96 is omitted because _BitInt(96) is 12 bytes with no
-// padding on 32-bit x86.
+// so the high-order storage holds padding bits even though the value width is
+// a multiple of CHAR_BIT.
 void test_unsigned_24() {
   // sizeof(_BitInt(24)) == 4 on x86_64; 8 padding bits.
   unsigned _BitInt(24) v = 0;
@@ -114,6 +113,18 @@ void test_unsigned_80() {
 }
 #    endif
 
+// 32-bit x86 packs _BitInt(96) into 12 bytes (no padding), so std::byteswap
+// accepts it there; gate the case out. sizeof isn't available to the
+// preprocessor, so this is a target check rather than a has-padding predicate.
+#    if __BITINT_MAXWIDTH__ >= 96 && !defined(__i386__)
+void test_unsigned_96() {
+  // sizeof(_BitInt(96)) == 16 here; 32 padding bits.
+  unsigned _BitInt(96) v = 0;
+  // 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
+
 #    if __BITINT_MAXWIDTH__ >= 112
 void test_unsigned_112() {
   // sizeof(_BitInt(112)) == 16 on x86_64; 16 padding bits.



More information about the libcxx-commits mailing list