2026-09-19 Jakub Jelinek <[email protected]>
P3104R6
* include/bits/version.def: Implement C++29 P3104R6 - Bit permutations.
(bitops): Change value from 202606 to 202607.
* include/bits/version.h: Regenerate.
* include/std/bit (std::bit_repeat, std::bit_reverse,
std::bit_compress, std::bit_expand): New function templates for C++29.
* src/c++23/std.cc.in (std::bit_repeat, std::bit_reverse,
std::bit_compress, std::bit_expand): New exports for C++29.
* testsuite/26_numerics/bit/bit.permute/bit_reverse.cc: New test.
* testsuite/26_numerics/bit/bit.permute/bit_repeat.cc: New test.
* testsuite/26_numerics/bit/bit.permute/bit_compress.cc: New test.
* testsuite/26_numerics/bit/bit.permute/bit_expand.cc: New test.
--- a/libstdc++-v3/include/bits/version.def 2026-09-14 18:15:14.380304280
+0200
+++ b/libstdc++-v3/include/bits/version.def 2026-09-18 12:52:53.354665068
+0200
@@ -890,10 +890,13 @@ ftms = {
ftms = {
name = bitops;
+ // 202606 P3793R2 Better shifting
+ // 202607 P3104R6 Bit permutations
values = {
- v = 202606;
+ v = 202607;
cxxmin = 29;
};
+ // 201907 P0553R4 Bit operations
values = {
v = 201907;
cxxmin = 20;
--- a/libstdc++-v3/include/bits/version.h 2026-09-14 18:16:26.698489949
+0200
+++ b/libstdc++-v3/include/bits/version.h 2026-09-18 12:52:58.583293839
+0200
@@ -990,9 +990,9 @@
#if !defined(__cpp_lib_bitops)
# if (__cplusplus > 202603L)
-# define __glibcxx_bitops 202606L
+# define __glibcxx_bitops 202607L
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_bitops)
-# define __cpp_lib_bitops 202606L
+# define __cpp_lib_bitops 202607L
# endif
# elif (__cplusplus >= 202002L)
# define __glibcxx_bitops 201907L
--- a/libstdc++-v3/include/std/bit 2026-09-11 09:31:04.134777224 +0200
+++ b/libstdc++-v3/include/std/bit 2026-09-18 17:10:09.921978829 +0200
@@ -515,6 +515,123 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return std::__bit_width(__x); }
#endif // defined (__cpp_lib_int_pow2)
+#if __cpp_lib_bitops >= 202607L // >= C++29
+ // [bit.permute], permutation
+ template<__unsigned_integer _Tp>
+ [[nodiscard]] constexpr _Tp
+ bit_repeat(_Tp __x, int __l)
+ {
+ __glibcxx_assert( __l > 0 );
+ constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+ if (__l >= _Nd)
+ return __x;
+ __x &= ((_Tp)1 << __l) - 1;
+ do
+ {
+ __x |= __x << __l;
+ __l <<= 1;
+ }
+ while (__l < _Nd);
+ return __x;
+ }
+
+ template<__unsigned_integer _Tp>
+ [[nodiscard]] constexpr _Tp
+ bit_reverse(_Tp __x) noexcept
+ {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_bitreverseg)
+ return __builtin_bitreverseg(__x);
+#else
+ constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+ if constexpr (_Nd % __CHAR_BIT__ == 0 && __CHAR_BIT__ == 8)
+ {
+ __x = std::byteswap(__x);
+ constexpr auto __m1 = std::bit_repeat<_Tp>(15, 8);
+ constexpr auto __m2 = std::bit_repeat<_Tp>(3, 4);
+ constexpr auto __m3 = std::bit_repeat<_Tp>(1, 2);
+ __x = ((__x >> 4) & __m1) | ((__x & __m1) << 4);
+ __x = ((__x >> 2) & __m2) | ((__x & __m2) << 2);
+ __x = ((__x >> 1) & __m3) | ((__x & __m3) << 1);
+ return __x;
+ }
+ else
+ {
+ _Tp __r = 0;
+ for (int __i = 0; __i < _Nd; ++__i)
+ {
+ __r <<= 1;
+ __r |= (__x & 1);
+ __x >>= 1;
+ }
+ return __r;
+ }
+#endif
+ }
+
+ template<__unsigned_integer _Tp>
+ [[nodiscard]] constexpr _Tp
+ bit_compress(_Tp __x, _Tp __m) noexcept
+ {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_elementwise_pext)
+ return __builtin_elementwise_pext(__x, __m);
+#else
+ constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+ // Based on "Compress, or Generalized Extract" in Hacker's Delight
+ __x &= __m;
+ _Tp __mk = ~__m << 1;
+ for (int __i = 1; __i < _Nd; __i <<= 1)
+ {
+ _Tp __mp = __mk;
+ for (int __j = 1; __j < _Nd; __j <<= 1)
+ __mp ^= __mp << __j;
+ _Tp __mv = __mp & __m;
+ __m = (__m ^ __mv) | (__mv >> __i);
+ _Tp __t = __x & __mv;
+ __x = (__x ^ __t) | (__t >> __i);
+ __mk = __mk & ~__mp;
+ }
+ return __x;
+#endif
+ }
+
+ template<__unsigned_integer _Tp>
+ [[nodiscard]] constexpr _Tp
+ bit_expand(_Tp __x, _Tp __m) noexcept
+ {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_elementwise_pdep)
+ return __builtin_elementwise_pdep(__x, __m);
+#else
+ constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+ if constexpr (_Nd == 1)
+ return __x & __m;
+ constexpr auto __log2_Nd
+ = _Nd == 1 ? 1 : (__gnu_cxx::__int_traits<unsigned>::__digits
+ - std::__countl_zero<unsigned>(_Nd - 1));
+ // Based on "Expand, or Generalized Insert" in Hacker's Delight
+ _Tp __m0 = __m;
+ _Tp __mk = ~__m << 1;
+ _Tp __array[__log2_Nd];
+ for (int __i = 0; __i < __log2_Nd; __i++)
+ {
+ _Tp __mp = __mk;
+ for (int __j = 1; __j < _Nd; __j <<= 1)
+ __mp ^= __mp << __j;
+ _Tp __mv = __mp & __m;
+ __array[__i] = __mv;
+ __m = (__m ^ __mv) | (__mv >> (_Tp(1) << __i));
+ __mk = __mk & ~__mp;
+ }
+ for (int __i = __log2_Nd - 1; __i >= 0; __i--)
+ {
+ _Tp __mv = __array[__i];
+ _Tp __t = __x << (_Tp(1) << __i);
+ __x = (__x & ~__mv) | (__t & __mv);
+ }
+ return __x & __m0;
+#endif
+ }
+#endif // __cpp_lib_bitops >= 202607L
+
#ifdef __cpp_lib_endian // C++ >= 20
/// Byte order constants
--- a/libstdc++-v3/src/c++23/std.cc.in 2026-09-11 09:31:04.134777224 +0200
+++ b/libstdc++-v3/src/c++23/std.cc.in 2026-09-19 19:17:15.890363477 +0200
@@ -699,6 +699,12 @@ export namespace std
using std::shl;
using std::shr;
#endif
+#if __cpp_lib_bitops >= 202607L // >= C++29
+ using std::bit_reverse;
+ using std::bit_repeat;
+ using std::bit_compress;
+ using std::bit_expand;
+#endif
}
// 22.9 <bitset>
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_reverse.cc
2026-09-18 15:05:47.705779245 +0200
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_reverse.cc
2026-09-18 15:48:35.514878450 +0200
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_reverse(x))
+{
+ constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+ static_assert( std::bit_reverse(UInt(0)) == UInt(0) );
+ static_assert( std::bit_reverse(UInt(~UInt(0))) == UInt(~UInt(0)) );
+ static_assert( std::bit_reverse(UInt(1)) == UInt(1) << (digits - 1) );
+ static_assert( std::bit_reverse(UInt(UInt(1) << (digits - 1))) == UInt(1) );
+ if constexpr (std::numeric_limits<UInt>::digits == 8)
+ static_assert( std::bit_reverse<UInt>(0x34u) == 0x2cu );
+ if constexpr (std::numeric_limits<UInt>::digits == 16)
+ static_assert( std::bit_reverse<UInt>(0x1234u) == 0x2c48u );
+ if constexpr (std::numeric_limits<UInt>::digits == 32)
+ static_assert( std::bit_reverse<UInt>(0x01234567u) == 0xe6a2c480u );
+ if constexpr (std::numeric_limits<UInt>::digits == 64)
+ static_assert( std::bit_reverse<UInt>(0x0123456789abcdefull) ==
0xf7b3d591e6a2c480ull );
+ if constexpr (std::numeric_limits<UInt>::digits == 128)
+ static_assert( std::bit_reverse<UInt>((UInt(0x0123456789abcdefull) << 64)
+ | 0x2468ace013579bdfull)
+ == ((UInt(0xfbd9eac807351624ull) << 64)
+ | 0xf7b3d591e6a2c480ull) );
+ if (std::bit_reverse(std::bit_reverse(x)) == x)
+ return x;
+ return 0;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_reverse(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_repeat.cc
2026-09-18 15:52:52.105498580 +0200
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_repeat.cc
2026-09-18 16:38:38.536710632 +0200
@@ -0,0 +1,125 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+// Detect whether std::bit_repeat(T(0), N) is a constant expression.
+template<typename T, auto N, typename = void>
+ struct bit_repeat_valid
+ : std::false_type { };
+
+template<typename T, auto N>
+ struct bit_repeat_valid<T, N, std::void_t<char[(std::bit_repeat(T(0), N) ==
T(0))]>>
+ : std::true_type { };
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_repeat(x, 1))
+{
+ constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+ static_assert( std::bit_repeat(UInt(0), 1) == UInt(0) );
+ static_assert( std::bit_repeat(UInt(0), digits) == UInt(0) );
+ static_assert( std::bit_repeat(UInt(0), digits * 6) == UInt(0) );
+ static_assert( std::bit_repeat(UInt(~UInt(0)), 1) == UInt(~UInt(0)) );
+ static_assert( std::bit_repeat(UInt(~UInt(0)), digits) == UInt(~UInt(0)) );
+ static_assert( std::bit_repeat(UInt(~UInt(0)), digits * 6) == UInt(~UInt(0))
);
+ static_assert( std::bit_repeat(UInt(1), 1) == UInt(~UInt(0)) );
+ static_assert( std::bit_repeat(UInt(~UInt(1)), 1) == UInt(0) );
+ static_assert( std::bit_repeat(std::bit_repeat(UInt(0x0123456789abcdefull),
3), 3)
+ == std::bit_repeat(UInt(0x0123456789abcdefull), 3) );
+ if constexpr (std::numeric_limits<UInt>::digits >= 8)
+ {
+ static_assert( (std::bit_repeat<UInt>(0x34, 3) & UInt(0xff)) == 0x24u );
+ static_assert( (std::bit_repeat<UInt>(0x71, 2) & UInt(0xff)) == 0x55u );
+ static_assert( (std::bit_repeat<UInt>(0xf2, 2) & UInt(0xff)) == 0xaau );
+ static_assert( (std::bit_repeat<UInt>(0xb3, 5) & UInt(0xff)) == 0x73u );
+ static_assert( (std::bit_repeat<UInt>(0xb3, 8) & UInt(0xff)) == 0xb3u );
+ }
+ if constexpr (std::numeric_limits<UInt>::digits >= 16)
+ {
+ static_assert( (std::bit_repeat<UInt>(0x1734, 3) & UInt(0xffff)) ==
0x4924u );
+ static_assert( (std::bit_repeat<UInt>(0x2071, 2) & UInt(0xffff)) ==
0x5555u );
+ static_assert( (std::bit_repeat<UInt>(0x52f2, 2) & UInt(0xffff)) ==
0xaaaau );
+ static_assert( (std::bit_repeat<UInt>(0x07b3, 5) & UInt(0xffff)) ==
0xce73u );
+ static_assert( (std::bit_repeat<UInt>(0x21b3, 8) & UInt(0xffff)) ==
0xb3b3u );
+ static_assert( (std::bit_repeat<UInt>(0xa2b3u, 16) & UInt(0xffff)) ==
0xa2b3u );
+ }
+ if constexpr (std::numeric_limits<UInt>::digits >= 32)
+ {
+ static_assert( (std::bit_repeat<UInt>(0x12345634u, 3) &
UInt(0xffffffffu)) == 0x24924924u );
+ static_assert( (std::bit_repeat<UInt>(0x23456771u, 2) &
UInt(0xffffffffu)) == 0x55555555u );
+ static_assert( (std::bit_repeat<UInt>(0x345678f2u, 2) &
UInt(0xffffffffu)) == 0xaaaaaaaau );
+ static_assert( (std::bit_repeat<UInt>(0x456789b3u, 5) &
UInt(0xffffffffu)) == 0xe739ce73u );
+ static_assert( (std::bit_repeat<UInt>(0x56789ab3u, 8) &
UInt(0xffffffffu)) == 0xb3b3b3b3u );
+ static_assert( (std::bit_repeat<UInt>(0x6789a2b3u, 16) &
UInt(0xffffffffu)) == 0xa2b3a2b3u );
+ static_assert( (std::bit_repeat<UInt>(0x2a4dda0eu, 32) &
UInt(0xffffffffu)) == 0x2a4dda0eu );
+ }
+ if constexpr (std::numeric_limits<UInt>::digits >= 64)
+ {
+ static_assert( (std::bit_repeat<UInt>(0x1122334455667734ull, 3) &
UInt(0xffffffffffffffffull)) == 0x4924924924924924ull );
+ static_assert( (std::bit_repeat<UInt>(0x2233445566778871ull, 2) &
UInt(0xffffffffffffffffull)) == 0x5555555555555555ull );
+ static_assert( (std::bit_repeat<UInt>(0x33445566778899f2ull, 2) &
UInt(0xffffffffffffffffull)) == 0xaaaaaaaaaaaaaaaaull );
+ static_assert( (std::bit_repeat<UInt>(0x445566778899aab3ull, 5) &
UInt(0xffffffffffffffffull)) == 0x39ce739ce739ce73ull );
+ static_assert( (std::bit_repeat<UInt>(0x5566778899aabbb3ull, 8) &
UInt(0xffffffffffffffffull)) == 0xb3b3b3b3b3b3b3b3ull );
+ static_assert( (std::bit_repeat<UInt>(0x66778899aabba2b3ull, 16) &
UInt(0xffffffffffffffffull)) == 0xa2b3a2b3a2b3a2b3ull );
+ static_assert( (std::bit_repeat<UInt>(0x778899aa2a4dda0eull, 32) &
UInt(0xffffffffffffffffull)) == 0x2a4dda0e2a4dda0eull );
+ }
+ if constexpr (std::numeric_limits<UInt>::digits == 128)
+ {
+ static_assert( std::bit_repeat<UInt>(1, 2)
+ == (UInt(0x5555555555555555ull) << 64) |
0x5555555555555555ull );
+ static_assert( std::bit_repeat<UInt>(2, 2)
+ == (UInt(0xaaaaaaaaaaaaaaaaull) << 64) |
0xaaaaaaaaaaaaaaaaull );
+ }
+ static_assert( bit_repeat_valid<UInt, 1>() );
+ static_assert( bit_repeat_valid<UInt, 17>() );
+ static_assert( bit_repeat_valid<UInt, digits>() );
+ static_assert( bit_repeat_valid<UInt, digits * 8>() );
+ static_assert( !bit_repeat_valid<UInt, 0>() );
+ static_assert( !bit_repeat_valid<UInt, -1>() );
+ static_assert( !bit_repeat_valid<UInt, -5>() );
+
+ return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_repeat(T, N) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_compress.cc
2026-09-18 16:42:30.677700824 +0200
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_compress.cc
2026-09-18 17:51:06.971617871 +0200
@@ -0,0 +1,87 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_compress(x, x))
+{
+ constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+ static_assert( std::bit_compress(UInt(0), UInt(0)) == UInt(0) );
+ static_assert( std::bit_compress(UInt(0x123456789abcdefull), UInt(0)) ==
UInt(0) );
+ static_assert( std::bit_compress(UInt(0x123456789abcdefull), UInt(~UInt(0)))
== UInt(0x123456789abcdefull) );
+ static_assert( std::bit_compress(UInt(0), UInt(0x123456789abcdefull)) ==
UInt(0) );
+ static_assert( std::bit_compress(UInt(~UInt(0)), UInt(~UInt(0))) ==
UInt(~UInt(0)) );
+ static_assert( std::bit_compress(UInt(~UInt(0)), UInt(0x123456789abcdefull)) ==
(UInt(1) << std::popcount(UInt(0x123456789abcdefull))) - 1 );
+ static_assert( digits < 16 || digits % 2 != 0 ||
std::bit_compress(std::bit_repeat(UInt(0x1234), 16), std::bit_repeat(UInt(1), 2)) ==
std::bit_repeat(UInt(0x46), 8) >> (digits / 2) );
+ static_assert( digits < 16 || digits % 2 != 0 ||
std::bit_compress(std::bit_repeat(UInt(0x1234), 16), std::bit_repeat(UInt(2), 2)) ==
std::bit_repeat(UInt(0x14), 8) >> (digits / 2) );
+ static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0xff)) ==
UInt(0xff) );
+ static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0x0f)) ==
UInt(0x0f) );
+ static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0xf0)) ==
UInt(0x0f) );
+ static_assert( digits % 2 != 0 || std::bit_compress(std::bit_repeat(UInt(2), 2),
std::bit_repeat(UInt(0xc), 4)) == std::bit_repeat(UInt(0x2), 2) >> (digits / 2)
);
+ static_assert( digits % 2 != 0 || std::bit_compress(UInt(~UInt(0)),
std::bit_repeat(UInt(2), 2)) == UInt(~UInt(0)) >> (digits / 2) );
+ if constexpr (digits >= 8)
+ {
+ static_assert( std::bit_compress(UInt(0xd4), UInt(0xbf)) == UInt(0x54) );
+ static_assert( std::bit_compress(UInt(0x66), UInt(0x1d)) == UInt(0x02) );
+ }
+ if constexpr (digits >= 16)
+ {
+ static_assert( std::bit_compress(UInt(0xebd4u), UInt(0x93bfu)) ==
UInt(0x05d4) );
+ static_assert( std::bit_compress(UInt(0xa166u), UInt(0x001du)) ==
UInt(2) );
+ }
+ if constexpr (digits >= 32)
+ {
+ static_assert( std::bit_compress(UInt(0x9daeebd4u), UInt(0xad8793bfu))
== UInt(0xbf5d4u) );
+ static_assert( std::bit_compress(UInt(0x979ba166u), UInt(0x54ca001du))
== UInt(0x3b2u) );
+ }
+ if constexpr (digits >= 64)
+ {
+ static_assert( std::bit_compress(UInt(0x5bd30f069daeebd4ull),
UInt(0x64f9a89bad8793bfull)) == UInt(0x13522bf5d4ull) );
+ static_assert( std::bit_compress(UInt(0xb5672499979ba166ull),
UInt(0xd315782354ca001dull)) == UInt(0x2ad0bb2ull) );
+ }
+ return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_compress(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
--- a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_expand.cc
2026-09-18 17:33:27.424621833 +0200
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_expand.cc
2026-09-18 18:08:54.689572006 +0200
@@ -0,0 +1,87 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_expand(x, x))
+{
+ constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+ static_assert( std::bit_expand(UInt(0), UInt(0)) == UInt(0) );
+ static_assert( std::bit_expand(UInt(0x123456789abcdefull), UInt(0)) ==
UInt(0) );
+ static_assert( std::bit_expand(UInt(0x123456789abcdefull), UInt(~UInt(0)))
== UInt(0x123456789abcdefull) );
+ static_assert( std::bit_expand(UInt(0), UInt(0x123456789abcdefull)) ==
UInt(0) );
+ static_assert( std::bit_expand(UInt(~UInt(0)), UInt(~UInt(0))) ==
UInt(~UInt(0)) );
+ static_assert( std::bit_expand(UInt((UInt(1) <<
std::popcount(UInt(0x123456789abcdefull))) - 1), UInt(0x123456789abcdefull)) ==
UInt(0x123456789abcdefull) );
+ static_assert( digits < 16 || std::bit_expand(std::bit_repeat(UInt(0x46),
8), std::bit_repeat(UInt(1), 2)) == std::bit_repeat(UInt(0x1014), 16) );
+ static_assert( digits < 16 || std::bit_expand(std::bit_repeat(UInt(0x14),
8), std::bit_repeat(UInt(2), 2)) == std::bit_repeat(UInt(0x0220), 16) );
+ static_assert( digits < 8 || std::bit_expand(UInt(0xff), UInt(0xff)) ==
UInt(0xff) );
+ static_assert( digits < 8 || std::bit_expand(UInt(0x0f), UInt(0xff)) ==
UInt(0x0f) );
+ static_assert( digits < 8 || std::bit_expand(UInt(0x0f), UInt(0xf0)) ==
UInt(0xf0) );
+ static_assert( std::bit_expand(std::bit_repeat(UInt(2), 2),
std::bit_repeat(UInt(0xc), 4)) == std::bit_repeat(UInt(0x8), 4) );
+ static_assert( std::bit_expand(std::bit_repeat(UInt(0x0f), 8),
std::bit_repeat(UInt(2), 2)) == std::bit_repeat(UInt(0xaa), 16) );
+ if constexpr (digits >= 8)
+ {
+ static_assert( std::bit_expand(UInt(0xd4), UInt(0xbf)) == UInt(0x94) );
+ static_assert( std::bit_expand(UInt(0x66), UInt(0x1d)) == UInt(0x0c) );
+ }
+ if constexpr (digits >= 16)
+ {
+ static_assert( std::bit_expand(UInt(0xebd4u), UInt(0x93bfu)) ==
UInt(0x1394) );
+ static_assert( std::bit_expand(UInt(0xa166u), UInt(0x001du)) ==
UInt(0xc) );
+ }
+ if constexpr (digits >= 32)
+ {
+ static_assert( std::bit_expand(UInt(0x9daeebd4u), UInt(0xad8793bfu)) ==
UInt(0xa9851394u) );
+ static_assert( std::bit_expand(UInt(0x979ba166u), UInt(0x54ca001du)) ==
UInt(0x448000cu) );
+ }
+ if constexpr (digits >= 64)
+ {
+ static_assert( std::bit_expand(UInt(0x5bd30f069daeebd4ull),
UInt(0x64f9a89bad8793bfull)) == UInt(0x4a1a092a9851394ull) );
+ static_assert( std::bit_expand(UInt(0xb5672499979ba166ull),
UInt(0xd315782354ca001dull)) == UInt(0xd01470200448000cull) );
+ }
+ return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_expand(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
Jakub