[libcxx-commits] [libcxx] [libc++] Fix possible out of range access in bitset (PR #121348)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 28 09:24:36 PDT 2025


https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/121348

>From d915d307db49adfc5fd0cc8c48c26bb7ca860eff Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 30 Dec 2024 12:19:19 -0500
Subject: [PATCH 1/8] Improve bitset::to_ullong Implementation

---
 libcxx/include/bitset | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 88dc0e08c995d..29aebfe55f674 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -136,6 +136,7 @@ template <size_t N> struct hash<std::bitset<N>>;
 #  include <__algorithm/fill.h>
 #  include <__algorithm/fill_n.h>
 #  include <__algorithm/find.h>
+#  include <__algorithm/min.h>
 #  include <__assert>
 #  include <__bit/countr.h>
 #  include <__bit/invert_if.h>
@@ -415,8 +416,9 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   unsigned long long __r = __first_[0];
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  for (size_t __i = 1; __i < sizeof(unsigned long long) / sizeof(__storage_type); ++__i)
-    __r |= static_cast<unsigned long long>(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT);
+  size_t __n_words = std::min<size_t>(_N_words, sizeof(unsigned long long) / sizeof(__storage_type));
+  for (size_t __i = 1; __i < __n_words; ++__i)
+    __r |= static_cast<unsigned long long>(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT * __i);
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
 }

>From 7a640a379074311de8b76af5c739ad59e381c531 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Tue, 31 Dec 2024 01:44:59 -0500
Subject: [PATCH 2/8] Make variable constant expression

---
 libcxx/include/bitset | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 29aebfe55f674..3464e3561ef83 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -416,7 +416,8 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   unsigned long long __r = __first_[0];
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  size_t __n_words = std::min<size_t>(_N_words, sizeof(unsigned long long) / sizeof(__storage_type));
+  const size_t __ull_words = sizeof(unsigned long long) / sizeof(__storage_type);
+  const size_t __n_words = _N_words < __ull_words ? _N_words : __ull_words;
   for (size_t __i = 1; __i < __n_words; ++__i)
     __r |= static_cast<unsigned long long>(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT * __i);
   _LIBCPP_DIAGNOSTIC_POP

>From 388789b1edef921f18975296f4cbd8f08364c126 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 1 Jan 2025 18:06:08 -0500
Subject: [PATCH 3/8] Apply @frederick-vs-ja suggestions to support 16-bit
 platforms

---
 libcxx/include/bitset | 71 +++++++++++++++++++++++++++++++------------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 3464e3561ef83..5c1d835a3e795 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -262,6 +262,8 @@ private:
 #  endif // _LIBCPP_CXX03_LANG
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(false_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type, false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type, true_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(false_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(true_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(true_type, false_type) const;
@@ -317,14 +319,23 @@ inline _LIBCPP_HIDE_FROM_ABI void __bitset<_N_words, _Size>::__init(unsigned lon
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
 #  ifndef _LIBCPP_CXX03_LANG
-#    if __SIZEOF_SIZE_T__ == 8
-    : __first_{__v}
-#    elif __SIZEOF_SIZE_T__ == 4
+#    if (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 1
+    : __first_{static_cast<__storage_type>(__v)}
+#    elif (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 2
+    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
+#    elif (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 4
+#      if _N_words == 2
+    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
+#      elif _N_words == 3
     : __first_{static_cast<__storage_type>(__v),
-               _Size >= 2 * __bits_per_word
-                   ? static_cast<__storage_type>(__v >> __bits_per_word)
-                   : static_cast<__storage_type>((__v >> __bits_per_word) &
-                                                 (__storage_type(1) << (_Size - __bits_per_word)) - 1)}
+               static_cast<__storage_type>(__v >> __bits_per_word),
+               static_cast<__storage_type>(__v >> (__bits_per_word * 2))}
+#      else
+    : __first_{static_cast<__storage_type>(__v),
+               static_cast<__storage_type>(__v >> __bits_per_word),
+               static_cast<__storage_type>(__v >> (__bits_per_word * 2)),
+               static_cast<__storage_type>(__v >> (__bits_per_word * 3))}
+#      endif
 #    else
 #      error This constructor has not been ported to this platform
 #    endif
@@ -378,15 +389,34 @@ __bitset<_N_words, _Size>::to_ulong(false_type) const {
   if (__i != __e)
     std::__throw_overflow_error("bitset to_ulong overflow error");
 
-  return __first_[0];
+  return to_ulong(true_type());
 }
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
 __bitset<_N_words, _Size>::to_ulong(true_type) const {
-  return __first_[0];
+  return to_ulong(true_type(), integral_constant<bool, sizeof(__storage_type) < sizeof(unsigned long)>());
+}
+
+template <size_t _N_words, size_t _Size>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
+__bitset<_N_words, _Size>::to_ulong(true_type, false_type) const {
+  return static_cast<unsigned long>(__first_[0]);
 }
 
+template <size_t _N_words, size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
+__bitset<_N_words, _Size>::to_ulong(true_type, true_type) const {
+  unsigned long __r = static_cast<unsigned long>(__first_[0]);
+  _LIBCPP_DIAGNOSTIC_PUSH
+  _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
+  const size_t __ul_words = sizeof(unsigned long) / sizeof(__storage_type);
+  const size_t __n_words  = _N_words < __ul_words ? _N_words : __ul_words;
+  for (size_t __i = 1; __i < __n_words; ++__i)
+    __r |= static_cast<unsigned long>(__first_[__i]) << (__bits_per_word * __i);
+  _LIBCPP_DIAGNOSTIC_POP
+  return __r;
+}
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::to_ullong(false_type) const {
@@ -407,19 +437,19 @@ __bitset<_N_words, _Size>::to_ullong(true_type) const {
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::to_ullong(true_type, false_type) const {
-  return __first_[0];
+  return static_cast<unsigned long long>(__first_[0]);
 }
 
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
-  unsigned long long __r = __first_[0];
+  unsigned long long __r = static_cast<unsigned long long>(__first_[0]);
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
   const size_t __ull_words = sizeof(unsigned long long) / sizeof(__storage_type);
-  const size_t __n_words = _N_words < __ull_words ? _N_words : __ull_words;
+  const size_t __n_words   = _N_words < __ull_words ? _N_words : __ull_words;
   for (size_t __i = 1; __i < __n_words; ++__i)
-    __r |= static_cast<unsigned long long>(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT * __i);
+    __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
 }
@@ -510,8 +540,11 @@ inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset() _NOEXCEPT : __first_(0)
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_(_Size == __bits_per_word ? static_cast<__storage_type>(__v)
-                                        : static_cast<__storage_type>(__v) & ((__storage_type(1) << _Size) - 1)) {}
+    : __first_(static_cast<__storage_type>(__v)) {
+  // Force __bits_per_word to be instantiated to avoid "gdb.error: There is no member or method named
+  // __bits_per_word"
+  (void)__bits_per_word;
+}
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void
@@ -538,12 +571,12 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<1, _Siz
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::to_ulong() const {
-  return __first_;
+  return static_cast<unsigned long>(__first_);
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __bitset<1, _Size>::to_ullong() const {
-  return __first_;
+  return static_cast<unsigned long long>(__first_);
 }
 
 template <size_t _Size>
@@ -607,8 +640,8 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return 0; }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return 0; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return 0UL; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return 0ULL; }
 
   template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>

>From 13fc42e1aeb80f96afe6ffaf6f2d7cdcc4cd41fe Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Fri, 3 Jan 2025 11:58:42 -0500
Subject: [PATCH 4/8] Fix gdb.error

---
 libcxx/include/bitset | 31 ++++++++++---------------------
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 5c1d835a3e795..7c84868f81472 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -147,6 +147,7 @@ template <size_t N> struct hash<std::bitset<N>>;
 #  include <__functional/hash.h>
 #  include <__functional/identity.h>
 #  include <__functional/unary_function.h>
+#  include <__type_traits/integral_constant.h>
 #  include <__type_traits/is_char_like_type.h>
 #  include <climits>
 #  include <stdexcept>
@@ -222,10 +223,10 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
-    return to_ulong(integral_constant < bool, _Size< sizeof(unsigned long) * CHAR_BIT>());
+    return to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
-    return to_ullong(integral_constant < bool, _Size< sizeof(unsigned long long) * CHAR_BIT>());
+    return to_ullong(_BoolConstant < _Size< sizeof(unsigned long long) * CHAR_BIT>());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return !__scan_bits(__bit_not()); }
@@ -384,9 +385,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<_N_words, _Siz
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
 __bitset<_N_words, _Size>::to_ulong(false_type) const {
-  __const_iterator __e = __make_iter(_Size);
-  __const_iterator __i = std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true);
-  if (__i != __e)
+  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
     std::__throw_overflow_error("bitset to_ulong overflow error");
 
   return to_ulong(true_type());
@@ -395,7 +394,7 @@ __bitset<_N_words, _Size>::to_ulong(false_type) const {
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
 __bitset<_N_words, _Size>::to_ulong(true_type) const {
-  return to_ulong(true_type(), integral_constant<bool, sizeof(__storage_type) < sizeof(unsigned long)>());
+  return to_ulong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long)>());
 }
 
 template <size_t _N_words, size_t _Size>
@@ -410,9 +409,7 @@ __bitset<_N_words, _Size>::to_ulong(true_type, true_type) const {
   unsigned long __r = static_cast<unsigned long>(__first_[0]);
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  const size_t __ul_words = sizeof(unsigned long) / sizeof(__storage_type);
-  const size_t __n_words  = _N_words < __ul_words ? _N_words : __ul_words;
-  for (size_t __i = 1; __i < __n_words; ++__i)
+  for (size_t __i = 1; __i < _N_words; ++__i)
     __r |= static_cast<unsigned long>(__first_[__i]) << (__bits_per_word * __i);
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
@@ -420,9 +417,7 @@ __bitset<_N_words, _Size>::to_ulong(true_type, true_type) const {
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::to_ullong(false_type) const {
-  __const_iterator __e = __make_iter(_Size);
-  __const_iterator __i = std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true);
-  if (__i != __e)
+  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
     std::__throw_overflow_error("bitset to_ullong overflow error");
 
   return to_ullong(true_type());
@@ -431,7 +426,7 @@ __bitset<_N_words, _Size>::to_ullong(false_type) const {
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::to_ullong(true_type) const {
-  return to_ullong(true_type(), integral_constant<bool, sizeof(__storage_type) < sizeof(unsigned long long)>());
+  return to_ullong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long long)>());
 }
 
 template <size_t _N_words, size_t _Size>
@@ -446,9 +441,7 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   unsigned long long __r = static_cast<unsigned long long>(__first_[0]);
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  const size_t __ull_words = sizeof(unsigned long long) / sizeof(__storage_type);
-  const size_t __n_words   = _N_words < __ull_words ? _N_words : __ull_words;
-  for (size_t __i = 1; __i < __n_words; ++__i)
+  for (size_t __i = 1; __i < _N_words; ++__i)
     __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
@@ -540,11 +533,7 @@ inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset() _NOEXCEPT : __first_(0)
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_(static_cast<__storage_type>(__v)) {
-  // Force __bits_per_word to be instantiated to avoid "gdb.error: There is no member or method named
-  // __bits_per_word"
-  (void)__bits_per_word;
-}
+    : __first_(_Size == __bits_per_word ? static_cast<__storage_type>(__v) : static_cast<__storage_type>(__v)) {}
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void

>From c2377de4ba3343829f8641aa8981976cc90dfa54 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 24 Feb 2025 13:22:31 -0500
Subject: [PATCH 5/8] Fix to_ulong to throw overflow_error as expected

---
 libcxx/include/bitset | 71 ++++++++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 25 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 7c84868f81472..97df86da7cc25 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -223,10 +223,10 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
-    return to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
+    return __to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
-    return to_ullong(_BoolConstant < _Size< sizeof(unsigned long long) * CHAR_BIT>());
+    return __to_ullong(_BoolConstant < _Size< sizeof(unsigned long long) * CHAR_BIT>());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return !__scan_bits(__bit_not()); }
@@ -261,14 +261,6 @@ private:
   void __init(unsigned long long __v, false_type) _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI void __init(unsigned long long __v, true_type) _NOEXCEPT;
 #  endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type, false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong(true_type, true_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(true_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(true_type, false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong(true_type, true_type) const;
 
   template <typename _Proj>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __scan_bits(_Proj __proj) const _NOEXCEPT {
@@ -286,6 +278,15 @@ private:
     }
     return false;
   }
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type, false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type, true_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, true_type) const;
 };
 
 template <size_t _N_words, size_t _Size>
@@ -384,28 +385,28 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<_N_words, _Siz
 
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
-__bitset<_N_words, _Size>::to_ulong(false_type) const {
+__bitset<_N_words, _Size>::__to_ulong(false_type) const {
   if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
-    std::__throw_overflow_error("bitset to_ulong overflow error");
+    std::__throw_overflow_error("bitset __to_ulong overflow error");
 
-  return to_ulong(true_type());
+  return __to_ulong(true_type());
 }
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
-__bitset<_N_words, _Size>::to_ulong(true_type) const {
-  return to_ulong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long)>());
+__bitset<_N_words, _Size>::__to_ulong(true_type) const {
+  return __to_ulong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long)>());
 }
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
-__bitset<_N_words, _Size>::to_ulong(true_type, false_type) const {
+__bitset<_N_words, _Size>::__to_ulong(true_type, false_type) const {
   return static_cast<unsigned long>(__first_[0]);
 }
 
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
-__bitset<_N_words, _Size>::to_ulong(true_type, true_type) const {
+__bitset<_N_words, _Size>::__to_ulong(true_type, true_type) const {
   unsigned long __r = static_cast<unsigned long>(__first_[0]);
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
@@ -414,34 +415,37 @@ __bitset<_N_words, _Size>::to_ulong(true_type, true_type) const {
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
 }
+
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<_N_words, _Size>::to_ullong(false_type) const {
+__bitset<_N_words, _Size>::__to_ullong(false_type) const {
   if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
-    std::__throw_overflow_error("bitset to_ullong overflow error");
+    std::__throw_overflow_error("bitset __to_ullong overflow error");
 
-  return to_ullong(true_type());
+  return __to_ullong(true_type());
 }
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<_N_words, _Size>::to_ullong(true_type) const {
-  return to_ullong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long long)>());
+__bitset<_N_words, _Size>::__to_ullong(true_type) const {
+  return __to_ullong(true_type(), _BoolConstant<sizeof(__storage_type) < sizeof(unsigned long long)>());
 }
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<_N_words, _Size>::to_ullong(true_type, false_type) const {
+__bitset<_N_words, _Size>::__to_ullong(true_type, false_type) const {
   return static_cast<unsigned long long>(__first_[0]);
 }
 
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
+__bitset<_N_words, _Size>::__to_ullong(true_type, true_type) const {
   unsigned long long __r = static_cast<unsigned long long>(__first_[0]);
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  for (size_t __i = 1; __i < _N_words; ++__i)
+  const size_t __ull_wrods = (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1;
+  const size_t __n_words   = _N_words < __ull_wrods ? _N_words : __ull_wrods;
+  for (size_t __i = 1; __i < __n_words; ++__i)
     __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
   _LIBCPP_DIAGNOSTIC_POP
   return __r;
@@ -526,6 +530,10 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
 
   _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
+
+private:
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type) const;
 };
 
 template <size_t _Size>
@@ -560,6 +568,19 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<1, _Siz
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::to_ulong() const {
+  return __to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
+}
+
+template <size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::__to_ulong(false_type) const {
+  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
+    __throw_overflow_error("__bitset<1, _Size>::__to_ulong overflow error");
+
+  return static_cast<unsigned long>(__first_);
+}
+
+template <size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::__to_ulong(true_type) const {
   return static_cast<unsigned long>(__first_);
 }
 

>From 5f60e7b52455aa8ba44997271963dbc2a5938276 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 14 May 2025 11:32:47 -0400
Subject: [PATCH 6/8] Address ldionne's review comments

---
 libcxx/include/bitset | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 97df86da7cc25..41977abfb0ad4 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -223,10 +223,10 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
-    return __to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
+    return __to_ulong(_BoolConstant<_Size < sizeof(unsigned long) * CHAR_BIT>());
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
-    return __to_ullong(_BoolConstant < _Size< sizeof(unsigned long long) * CHAR_BIT>());
+    return __to_ullong(_BoolConstant<_Size < sizeof(unsigned long long) * CHAR_BIT>());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return !__scan_bits(__bit_not()); }
@@ -321,11 +321,11 @@ inline _LIBCPP_HIDE_FROM_ABI void __bitset<_N_words, _Size>::__init(unsigned lon
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
 #  ifndef _LIBCPP_CXX03_LANG
-#    if (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 1
+#    if __SIZEOF_LONG_LONG__ <= __SIZEOF_SIZE_T__
     : __first_{static_cast<__storage_type>(__v)}
-#    elif (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 2
+#    elif __SIZEOF_LONG_LONG__ <= 2 * __SIZEOF_SIZE_T__
     : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
-#    elif (__SIZEOF_LONG_LONG__ + __SIZEOF_SIZE_T__ - 1) / __SIZEOF_SIZE_T__ == 4
+#    elif __SIZEOF_LONG_LONG__ <= 4 * __SIZEOF_SIZE_T__
 #      if _N_words == 2
     : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
 #      elif _N_words == 3

>From af8b04a1dfad1a8b0df1415e9443b263ad56789b Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 15 May 2025 20:55:36 -0400
Subject: [PATCH 7/8] Fix preprocessing

---
 libcxx/include/bitset | 92 +++++++++++++++++++++++++++++--------------
 1 file changed, 62 insertions(+), 30 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index 41977abfb0ad4..ea57aadd629c4 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -147,8 +147,10 @@ template <size_t N> struct hash<std::bitset<N>>;
 #  include <__functional/hash.h>
 #  include <__functional/identity.h>
 #  include <__functional/unary_function.h>
+#  include <__type_traits/enable_if.h>
 #  include <__type_traits/integral_constant.h>
 #  include <__type_traits/is_char_like_type.h>
+#  include <__utility/integer_sequence.h>
 #  include <climits>
 #  include <stdexcept>
 #  include <string_view>
@@ -223,10 +225,10 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
-    return __to_ulong(_BoolConstant<_Size < sizeof(unsigned long) * CHAR_BIT>());
+    return __to_ulong(_BoolConstant<_Size <= sizeof(unsigned long) * CHAR_BIT>());
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
-    return __to_ullong(_BoolConstant<_Size < sizeof(unsigned long long) * CHAR_BIT>());
+    return __to_ullong(_BoolConstant<_Size <= sizeof(unsigned long long) * CHAR_BIT>());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return !__scan_bits(__bit_not()); }
@@ -287,6 +289,11 @@ private:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, false_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, true_type) const;
+#  if _LIBCPP_STD_VER >= 14
+  template <size_t... _Indices>
+  _LIBCPP_HIDE_FROM_ABI constexpr __bitset(unsigned long long __v, std::index_sequence<_Indices...>) _NOEXCEPT
+      : __first_{static_cast<__storage_type>(__v >> (_Indices * __bits_per_word))...} {}
+#  endif
 };
 
 template <size_t _N_words, size_t _Size>
@@ -318,35 +325,47 @@ inline _LIBCPP_HIDE_FROM_ABI void __bitset<_N_words, _Size>::__init(unsigned lon
 
 #  endif // _LIBCPP_CXX03_LANG
 
+#  ifdef _LIBCPP_CXX03_LANG
+template <size_t _N_words, size_t _Size>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT {
+  __init(__v, _BoolConstant<sizeof(unsigned long long) == sizeof(__storage_type)>());
+}
+#  elif _LIBCPP_STD_VER >= 14
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-#  ifndef _LIBCPP_CXX03_LANG
+    : __bitset{__v,
+               std::make_index_sequence<
+                   std::min<size_t>(_N_words, (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1)>{}} {}
+#  else
 #    if __SIZEOF_LONG_LONG__ <= __SIZEOF_SIZE_T__
-    : __first_{static_cast<__storage_type>(__v)}
-#    elif __SIZEOF_LONG_LONG__ <= 2 * __SIZEOF_SIZE_T__
-    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
-#    elif __SIZEOF_LONG_LONG__ <= 4 * __SIZEOF_SIZE_T__
-#      if _N_words == 2
-    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)}
-#      elif _N_words == 3
+template <size_t _N_words, size_t _Size>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
+    : __first_{static_cast<__storage_type>(__v)} {}
+#    elif __SIZEOF_LONG_LONG__ == 2 * __SIZEOF_SIZE_T__
+template <size_t _N_words, size_t _Size>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
+    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)} {}
+#    elif __SIZEOF_LONG_LONG__ == 4 * __SIZEOF_SIZE_T__
+template <size_t _N_words, size_t _Size, __enable_if_t<_N_words == 2, int> = 0>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
+    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)} {}
+
+template <size_t _N_words, size_t _Size, __enable_if_t<_N_words == 3, int> = 0>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
     : __first_{static_cast<__storage_type>(__v),
                static_cast<__storage_type>(__v >> __bits_per_word),
-               static_cast<__storage_type>(__v >> (__bits_per_word * 2))}
-#      else
+               static_cast<__storage_type>(__v >> (__bits_per_word * 2))} {}
+
+template <size_t _N_words, size_t _Size, __enable_if_t<_N_words >= 4, int> = 0>
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
     : __first_{static_cast<__storage_type>(__v),
                static_cast<__storage_type>(__v >> __bits_per_word),
                static_cast<__storage_type>(__v >> (__bits_per_word * 2)),
-               static_cast<__storage_type>(__v >> (__bits_per_word * 3))}
-#      endif
+               static_cast<__storage_type>(__v >> (__bits_per_word * 3))} {}
 #    else
 #      error This constructor has not been ported to this platform
 #    endif
-#  endif
-{
-#  ifdef _LIBCPP_CXX03_LANG
-  __init(__v, integral_constant<bool, sizeof(unsigned long long) <= sizeof(__storage_type)>());
-#  endif
-}
+#  endif // _LIBCPP_CXX03_LANG
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void
@@ -407,12 +426,11 @@ __bitset<_N_words, _Size>::__to_ulong(true_type, false_type) const {
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long
 __bitset<_N_words, _Size>::__to_ulong(true_type, true_type) const {
-  unsigned long __r = static_cast<unsigned long>(__first_[0]);
-  _LIBCPP_DIAGNOSTIC_PUSH
-  _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
-  for (size_t __i = 1; __i < _N_words; ++__i)
+  const size_t __ul_wrods = (sizeof(unsigned long) - 1) / sizeof(__storage_type) + 1;
+  const size_t __n_words  = _N_words < __ul_wrods ? _N_words : __ul_wrods;
+  unsigned long __r       = static_cast<unsigned long>(__first_[0]);
+  for (size_t __i = 1; __i < __n_words; ++__i)
     __r |= static_cast<unsigned long>(__first_[__i]) << (__bits_per_word * __i);
-  _LIBCPP_DIAGNOSTIC_POP
   return __r;
 }
 
@@ -440,14 +458,11 @@ __bitset<_N_words, _Size>::__to_ullong(true_type, false_type) const {
 template <size_t _N_words, size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
 __bitset<_N_words, _Size>::__to_ullong(true_type, true_type) const {
-  unsigned long long __r = static_cast<unsigned long long>(__first_[0]);
-  _LIBCPP_DIAGNOSTIC_PUSH
-  _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshift-count-overflow")
   const size_t __ull_wrods = (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1;
   const size_t __n_words   = _N_words < __ull_wrods ? _N_words : __ull_wrods;
+  unsigned long long __r   = static_cast<unsigned long long>(__first_[0]);
   for (size_t __i = 1; __i < __n_words; ++__i)
     __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
-  _LIBCPP_DIAGNOSTIC_POP
   return __r;
 }
 
@@ -534,6 +549,8 @@ protected:
 private:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(false_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(false_type) const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type) const;
 };
 
 template <size_t _Size>
@@ -568,7 +585,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<1, _Siz
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::to_ulong() const {
-  return __to_ulong(_BoolConstant < _Size< sizeof(unsigned long) * CHAR_BIT>());
+  return __to_ulong(_BoolConstant<_Size <= sizeof(unsigned long) * CHAR_BIT>());
 }
 
 template <size_t _Size>
@@ -586,6 +603,21 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _S
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __bitset<1, _Size>::to_ullong() const {
+  return __to_ullong(_BoolConstant<_Size <= sizeof(unsigned long long) * CHAR_BIT>());
+}
+
+template <size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
+__bitset<1, _Size>::__to_ullong(false_type) const {
+  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
+    __throw_overflow_error("__bitset<1, _Size>::__to_ullong overflow error");
+
+  return static_cast<unsigned long long>(__first_);
+}
+
+template <size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
+__bitset<1, _Size>::__to_ullong(true_type) const {
   return static_cast<unsigned long long>(__first_);
 }
 

>From 352b0110582301026f1fcd72000c1270f5a8d510 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 21 May 2025 16:20:23 -0400
Subject: [PATCH 8/8] Address ldionne's comments

---
 libcxx/include/bitset                         | 245 ++++++++++--------
 .../bitset.members/to_ullong.pass.cpp         |  67 +++--
 .../bitset.members/to_ulong.pass.cpp          |  65 +++--
 3 files changed, 224 insertions(+), 153 deletions(-)

diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index ea57aadd629c4..0dc371bae4383 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -80,7 +80,7 @@ public:
     constexpr bool operator[](size_t pos) const;
     reference operator[](size_t pos);            // constexpr since C++23
     unsigned long to_ulong() const;              // constexpr since C++23
-    unsigned long long to_ullong() const;        // constexpr since C++23
+    unsigned long long to_ullong() const;        // since C++11, constexpr since C++23
     template <class charT, class traits, class Allocator> // constexpr since C++23
         basic_string<charT, traits, Allocator> to_string(charT zero = charT('0'), charT one = charT('1')) const;
     template <class charT, class traits> // constexpr since C++23
@@ -147,6 +147,7 @@ template <size_t N> struct hash<std::bitset<N>>;
 #  include <__functional/hash.h>
 #  include <__functional/identity.h>
 #  include <__functional/unary_function.h>
+#  include <__tuple/tuple_indices.h>
 #  include <__type_traits/enable_if.h>
 #  include <__type_traits/integral_constant.h>
 #  include <__type_traits/is_char_like_type.h>
@@ -224,12 +225,66 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void operator^=(const __bitset& __v) _NOEXCEPT;
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
+
+  // unsigned long spans only one word
+  template <typename _StorageType                                             = __storage_type,
+            __enable_if_t<sizeof(_StorageType) >= sizeof(unsigned long), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong() const {
+    return static_cast<unsigned long>(__first_[0]);
+  }
+
+  // unsigned long may span multiple words which are concatenated to form the result
+  template <typename _StorageType                                            = __storage_type,
+            __enable_if_t<sizeof(_StorageType) < sizeof(unsigned long), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong() const {
+    const size_t __ul_words = (sizeof(unsigned long) - 1) / sizeof(__storage_type) + 1;
+    const size_t __n_words  = _N_words < __ul_words ? _N_words : __ul_words;
+    unsigned long __r       = static_cast<unsigned long>(__first_[0]);
+    for (size_t __i = 1; __i < __n_words; ++__i)
+      __r |= static_cast<unsigned long>(__first_[__i]) << (__bits_per_word * __i);
+    return __r;
+  }
+
+  // _Bit_size > sizeof(unsigned long) * CHAR_BIT: overflow check needed
+  template <size_t _Bit_size = _Size, __enable_if_t<(_Bit_size > sizeof(unsigned long) * CHAR_BIT), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
+    if (auto __e = __make_iter(_Bit_size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
+      std::__throw_overflow_error("__bitset<_N_words, _Size>::__to_ulong overflow error");
+
+    return __to_ulong();
+  }
+
+  // _Bit_size <= sizeof(unsigned long) * CHAR_BIT: no overflow check needed
+  template <size_t _Bit_size = _Size, __enable_if_t<(_Bit_size <= sizeof(unsigned long) * CHAR_BIT), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
-    return __to_ulong(_BoolConstant<_Size <= sizeof(unsigned long) * CHAR_BIT>());
+    return __to_ulong();
   }
+
+#  ifndef _LIBCPP_CXX03_LANG
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
-    return __to_ullong(_BoolConstant<_Size <= sizeof(unsigned long long) * CHAR_BIT>());
+    // Check for overflow if _Size does not fit in unsigned long long
+    if _LIBCPP_CONSTEXPR (_Size > sizeof(unsigned long long) * CHAR_BIT) {
+      if (auto __e = __make_iter(_Size);
+          std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
+        std::__throw_overflow_error("__bitset<_N_words, _Size>::__to_ullong overflow error");
+    }
+
+    // At this point, the effective bitset size (excluding leading zeros) fits in unsigned long long
+
+    if _LIBCPP_CONSTEXPR (sizeof(__storage_type) >= sizeof(unsigned long long)) {
+      // If __storage_type is at least as large as unsigned long long, the result spans only one word
+      return static_cast<unsigned long long>(__first_[0]);
+    } else {
+      // Otherwise, the result spans multiple words which are concatenated
+      const size_t __ull_words = (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1;
+      const size_t __n_words   = _N_words < __ull_words ? _N_words : __ull_words;
+      unsigned long long __r   = static_cast<unsigned long long>(__first_[0]);
+      for (size_t __i = 1; __i < __n_words; ++__i)
+        __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
+      return __r;
+    }
   }
+#  endif
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return !__scan_bits(__bit_not()); }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT {
@@ -262,7 +317,6 @@ private:
 #  ifdef _LIBCPP_CXX03_LANG
   void __init(unsigned long long __v, false_type) _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI void __init(unsigned long long __v, true_type) _NOEXCEPT;
-#  endif // _LIBCPP_CXX03_LANG
 
   template <typename _Proj>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __scan_bits(_Proj __proj) const _NOEXCEPT {
@@ -289,11 +343,12 @@ private:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, false_type) const;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type, true_type) const;
-#  if _LIBCPP_STD_VER >= 14
+
+#  else
   template <size_t... _Indices>
-  _LIBCPP_HIDE_FROM_ABI constexpr __bitset(unsigned long long __v, std::index_sequence<_Indices...>) _NOEXCEPT
+  _LIBCPP_HIDE_FROM_ABI constexpr __bitset(unsigned long long __v, std::__tuple_indices<_Indices...>) _NOEXCEPT
       : __first_{static_cast<__storage_type>(__v >> (_Indices * __bits_per_word))...} {}
-#  endif
+#  endif // _LIBCPP_CXX03_LANG
 };
 
 template <size_t _N_words, size_t _Size>
@@ -325,47 +380,20 @@ inline _LIBCPP_HIDE_FROM_ABI void __bitset<_N_words, _Size>::__init(unsigned lon
 
 #  endif // _LIBCPP_CXX03_LANG
 
-#  ifdef _LIBCPP_CXX03_LANG
 template <size_t _N_words, size_t _Size>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT {
+inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
+#  ifndef _LIBCPP_CXX03_LANG
+    : __bitset(__v,
+               std::__make_indices_imp< (_N_words < (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1)
+                                            ? _N_words
+                                            : (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1,
+                                        0>{})
+#  endif
+{
+#  ifdef _LIBCPP_CXX03_LANG
   __init(__v, _BoolConstant<sizeof(unsigned long long) == sizeof(__storage_type)>());
+#  endif
 }
-#  elif _LIBCPP_STD_VER >= 14
-template <size_t _N_words, size_t _Size>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __bitset{__v,
-               std::make_index_sequence<
-                   std::min<size_t>(_N_words, (sizeof(unsigned long long) - 1) / sizeof(__storage_type) + 1)>{}} {}
-#  else
-#    if __SIZEOF_LONG_LONG__ <= __SIZEOF_SIZE_T__
-template <size_t _N_words, size_t _Size>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_{static_cast<__storage_type>(__v)} {}
-#    elif __SIZEOF_LONG_LONG__ == 2 * __SIZEOF_SIZE_T__
-template <size_t _N_words, size_t _Size>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)} {}
-#    elif __SIZEOF_LONG_LONG__ == 4 * __SIZEOF_SIZE_T__
-template <size_t _N_words, size_t _Size, __enable_if_t<_N_words == 2, int> = 0>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_{static_cast<__storage_type>(__v), static_cast<__storage_type>(__v >> __bits_per_word)} {}
-
-template <size_t _N_words, size_t _Size, __enable_if_t<_N_words == 3, int> = 0>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_{static_cast<__storage_type>(__v),
-               static_cast<__storage_type>(__v >> __bits_per_word),
-               static_cast<__storage_type>(__v >> (__bits_per_word * 2))} {}
-
-template <size_t _N_words, size_t _Size, __enable_if_t<_N_words >= 4, int> = 0>
-inline _LIBCPP_CONSTEXPR __bitset<_N_words, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
-    : __first_{static_cast<__storage_type>(__v),
-               static_cast<__storage_type>(__v >> __bits_per_word),
-               static_cast<__storage_type>(__v >> (__bits_per_word * 2)),
-               static_cast<__storage_type>(__v >> (__bits_per_word * 3))} {}
-#    else
-#      error This constructor has not been ported to this platform
-#    endif
-#  endif // _LIBCPP_CXX03_LANG
 
 template <size_t _N_words, size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void
@@ -464,6 +492,38 @@ __bitset<_N_words, _Size>::__to_ullong(true_type, true_type) const {
   for (size_t __i = 1; __i < __n_words; ++__i)
     __r |= static_cast<unsigned long long>(__first_[__i]) << (__bits_per_word * __i);
   return __r;
+
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::all() const _NOEXCEPT {
+  // do middle whole words
+  size_t __n                  = _Size;
+  __const_storage_pointer __p = __first_;
+  for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
+    if (~*__p)
+      return false;
+  // do last partial word
+  if (__n > 0) {
+    __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
+    if (~*__p & __m)
+      return false;
+  }
+  return true;
+}
+
+template <size_t _N_words, size_t _Size>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::any() const _NOEXCEPT {
+  // do middle whole words
+  size_t __n                  = _Size;
+  __const_storage_pointer __p = __first_;
+  for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
+    if (*__p)
+      return true;
+  // do last partial word
+  if (__n > 0) {
+    __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
+    if (*__p & __m)
+      return true;
+  }
+  return false;
 }
 
 template <size_t _N_words, size_t _Size>
@@ -524,8 +584,32 @@ protected:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT;
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const;
+  template <size_t _Bit_size = _Size, __enable_if_t<(_Bit_size > sizeof(unsigned long) * CHAR_BIT), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
+    if (auto __e = __make_iter(_Bit_size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
+      __throw_overflow_error("__bitset<1, _Size>::to_ulong overflow error");
+
+    return static_cast<unsigned long>(__first_);
+  }
+
+  template <size_t _Bit_size = _Size, __enable_if_t<(_Bit_size <= sizeof(unsigned long) * CHAR_BIT), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const {
+    return static_cast<unsigned long>(__first_);
+  }
+
+#  ifndef _LIBCPP_CXX03_LANG
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
+    // If _Size exceeds the size of unsigned long long, check for overflow
+    if _LIBCPP_CONSTEXPR (_Size > sizeof(unsigned long long) * CHAR_BIT) {
+      if (auto __e = __make_iter(_Size);
+          std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
+        __throw_overflow_error("__bitset<1, _Size>::to_ullong overflow error");
+    }
+
+    // If _Size fits or no overflow, directly cast to unsigned long long
+    return static_cast<unsigned long long>(__first_);
+  }
+#  endif
 
   template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
@@ -545,12 +629,6 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
 
   _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
-
-private:
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __to_ulong(true_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(false_type) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __to_ullong(true_type) const;
 };
 
 template <size_t _Size>
@@ -558,6 +636,9 @@ inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset() _NOEXCEPT : __first_(0)
 
 template <size_t _Size>
 inline _LIBCPP_CONSTEXPR __bitset<1, _Size>::__bitset(unsigned long long __v) _NOEXCEPT
+    // TODO: This is a workaround for a GCC bug causing stage1 CI (generic-gcc, gcc-14, g++-14)
+    // failure due to __bits_per_word lookup failure if not referenced here.
+    // See: https://github.com/llvm/llvm-project/actions/runs/15071518915/job/42368867929?pr=121348#logs
     : __first_(_Size == __bits_per_word ? static_cast<__storage_type>(__v) : static_cast<__storage_type>(__v)) {}
 
 template <size_t _Size>
@@ -583,44 +664,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __bitset<1, _Siz
   __first_ ^= ~__storage_type(0) >> (__bits_per_word - _Size);
 }
 
-template <size_t _Size>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::to_ulong() const {
-  return __to_ulong(_BoolConstant<_Size <= sizeof(unsigned long) * CHAR_BIT>());
-}
-
-template <size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::__to_ulong(false_type) const {
-  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long) * CHAR_BIT), __e, true) != __e)
-    __throw_overflow_error("__bitset<1, _Size>::__to_ulong overflow error");
-
-  return static_cast<unsigned long>(__first_);
-}
-
-template <size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long __bitset<1, _Size>::__to_ulong(true_type) const {
-  return static_cast<unsigned long>(__first_);
-}
-
-template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long __bitset<1, _Size>::to_ullong() const {
-  return __to_ullong(_BoolConstant<_Size <= sizeof(unsigned long long) * CHAR_BIT>());
-}
-
-template <size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<1, _Size>::__to_ullong(false_type) const {
-  if (auto __e = __make_iter(_Size); std::find(__make_iter(sizeof(unsigned long long) * CHAR_BIT), __e, true) != __e)
-    __throw_overflow_error("__bitset<1, _Size>::__to_ullong overflow error");
-
-  return static_cast<unsigned long long>(__first_);
-}
-
-template <size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long
-__bitset<1, _Size>::__to_ullong(true_type) const {
-  return static_cast<unsigned long long>(__first_);
-}
-
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<1, _Size>::all() const _NOEXCEPT {
   __storage_type __m = ~__storage_type(0) >> (__bits_per_word - _Size);
@@ -683,7 +726,9 @@ protected:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void flip() _NOEXCEPT {}
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return 0UL; }
+#  ifndef _LIBCPP_CXX03_LANG
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return 0ULL; }
+#  endif
 
   template <bool _Sparse, class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
@@ -794,8 +839,12 @@ public:
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
     return __base::__make_ref(__p);
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return __base::to_ulong(); }
+#  ifndef _LIBCPP_CXX03_LANG
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const {
+    return __base::to_ullong();
+  }
+#  endif
   template <class _CharT, class _Traits, class _Allocator>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
   to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const;
@@ -931,16 +980,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>
   return *this;
 }
 
-template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long bitset<_Size>::to_ulong() const {
-  return __base::to_ulong();
-}
-
-template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long bitset<_Size>::to_ullong() const {
-  return __base::to_ullong();
-}
-
 template <size_t _Size>
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator>
diff --git a/libcxx/test/std/utilities/template.bitset/bitset.members/to_ullong.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.members/to_ullong.pass.cpp
index cbc8da96be1b1..485ca9ccf8a34 100644
--- a/libcxx/test/std/utilities/template.bitset/bitset.members/to_ullong.pass.cpp
+++ b/libcxx/test/std/utilities/template.bitset/bitset.members/to_ullong.pass.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: c++03, no-exceptions
+
 // unsigned long long to_ullong() const; // constexpr since C++23
 
 #include <bitset>
@@ -18,31 +20,32 @@
 
 template <std::size_t N>
 TEST_CONSTEXPR_CXX23 void test_to_ullong() {
-    const std::size_t M = sizeof(unsigned long long) * CHAR_BIT < N ? sizeof(unsigned long long) * CHAR_BIT : N;
-    const bool is_M_zero = std::integral_constant<bool, M == 0>::value; // avoid compiler warnings
-    const std::size_t X = is_M_zero ? sizeof(unsigned long long) * CHAR_BIT - 1 : sizeof(unsigned long long) * CHAR_BIT - M;
-    const unsigned long long max = is_M_zero ? 0 : (unsigned long long)(-1) >> X;
-    unsigned long long tests[] = {
-        0,
-        std::min<unsigned long long>(1, max),
-        std::min<unsigned long long>(2, max),
-        std::min<unsigned long long>(3, max),
-        std::min(max, max-3),
-        std::min(max, max-2),
-        std::min(max, max-1),
-        max
-    };
-    for (unsigned long long j : tests) {
-         std::bitset<N> v(j);
-        assert(j == v.to_ullong());
-    }
-    { // test values bigger than can fit into the bitset
-        const unsigned long long val = 0x55AAAAFFFFAAAA55ULL;
-        const bool canFit = N < sizeof(unsigned long long) * CHAR_BIT;
-        const unsigned long long mask = canFit ? (1ULL << (canFit ? N : 0)) - 1 : (unsigned long long)(-1); // avoid compiler warnings
-        std::bitset<N> v(val);
-        assert(v.to_ullong() == (val & mask)); // we shouldn't return bit patterns from outside the limits of the bitset.
-    }
+  const std::size_t M  = sizeof(unsigned long long) * CHAR_BIT < N ? sizeof(unsigned long long) * CHAR_BIT : N;
+  const bool is_M_zero = std::integral_constant < bool, M == 0 > ::value; // avoid compiler warnings
+  const std::size_t X =
+      is_M_zero ? sizeof(unsigned long long) * CHAR_BIT - 1 : sizeof(unsigned long long) * CHAR_BIT - M;
+  const unsigned long long max = is_M_zero ? 0 : (unsigned long long)(-1) >> X;
+  unsigned long long tests[]   = {
+      0,
+      std::min<unsigned long long>(1, max),
+      std::min<unsigned long long>(2, max),
+      std::min<unsigned long long>(3, max),
+      std::min(max, max - 3),
+      std::min(max, max - 2),
+      std::min(max, max - 1),
+      max};
+  for (unsigned long long j : tests) {
+    std::bitset<N> v(j);
+    assert(j == v.to_ullong());
+  }
+  { // test values bigger than can fit into the bitset
+    const unsigned long long val = 0x55AAAAFFFFAAAA55ULL;
+    const bool canFit            = N < sizeof(unsigned long long) * CHAR_BIT;
+    const unsigned long long mask =
+        canFit ? (1ULL << (canFit ? N : 0)) - 1 : (unsigned long long)(-1); // avoid compiler warnings
+    std::bitset<N> v(val);
+    assert(v.to_ullong() == (val & mask)); // we shouldn't return bit patterns from outside the limits of the bitset.
+  }
 }
 
 TEST_CONSTEXPR_CXX23 bool test() {
@@ -56,6 +59,20 @@ TEST_CONSTEXPR_CXX23 bool test() {
   test_to_ullong<65>();
   test_to_ullong<1000>();
 
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    // bitset has true bits beyond the size of unsigned long long
+    std::bitset<std::numeric_limits<unsigned long long>::digits + 1> q{0};
+    q.flip();
+    try {
+      q.to_ullong(); // throws
+      assert(false);
+    } catch (const std::overflow_error&) {
+      // expected
+    } catch (...) {
+      assert(false);
+    }
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/utilities/template.bitset/bitset.members/to_ulong.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.members/to_ulong.pass.cpp
index 17a5e7eb51aa2..977fa67dcd9bb 100644
--- a/libcxx/test/std/utilities/template.bitset/bitset.members/to_ulong.pass.cpp
+++ b/libcxx/test/std/utilities/template.bitset/bitset.members/to_ulong.pass.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: no-exceptions
+
 // unsigned long to_ulong() const; // constexpr since C++23
 
 #include <bitset>
@@ -19,32 +21,31 @@
 
 template <std::size_t N>
 TEST_CONSTEXPR_CXX23 void test_to_ulong() {
-    const std::size_t M = sizeof(unsigned long) * CHAR_BIT < N ? sizeof(unsigned long) * CHAR_BIT : N;
-    const bool is_M_zero = std::integral_constant<bool, M == 0>::value; // avoid compiler warnings
-    const std::size_t X = is_M_zero ? sizeof(unsigned long) * CHAR_BIT - 1 : sizeof(unsigned long) * CHAR_BIT - M;
-    const std::size_t max = is_M_zero ? 0 : std::size_t(std::numeric_limits<unsigned long>::max()) >> X;
-    std::size_t tests[] = {
-        0,
-        std::min<std::size_t>(1, max),
-        std::min<std::size_t>(2, max),
-        std::min<std::size_t>(3, max),
-        std::min(max, max-3),
-        std::min(max, max-2),
-        std::min(max, max-1),
-        max
-    };
-    for (std::size_t j : tests) {
-        std::bitset<N> v(j);
-        assert(j == v.to_ulong());
-    }
+  const std::size_t M   = sizeof(unsigned long) * CHAR_BIT < N ? sizeof(unsigned long) * CHAR_BIT : N;
+  const bool is_M_zero  = std::integral_constant < bool, M == 0 > ::value; // avoid compiler warnings
+  const std::size_t X   = is_M_zero ? sizeof(unsigned long) * CHAR_BIT - 1 : sizeof(unsigned long) * CHAR_BIT - M;
+  const std::size_t max = is_M_zero ? 0 : std::size_t(std::numeric_limits<unsigned long>::max()) >> X;
+  std::size_t tests[]   = {
+      0,
+      std::min<std::size_t>(1, max),
+      std::min<std::size_t>(2, max),
+      std::min<std::size_t>(3, max),
+      std::min(max, max - 3),
+      std::min(max, max - 2),
+      std::min(max, max - 1),
+      max};
+  for (std::size_t j : tests) {
+    std::bitset<N> v(j);
+    assert(j == v.to_ulong());
+  }
 
-    { // test values bigger than can fit into the bitset
-        const unsigned long val = 0x5AFFFFA5UL;
-        const bool canFit = N < sizeof(unsigned long) * CHAR_BIT;
-        const unsigned long mask = canFit ? (1UL << (canFit ? N : 0)) - 1 : (unsigned long)(-1); // avoid compiler warnings
-        std::bitset<N> v(val);
-        assert(v.to_ulong() == (val & mask)); // we shouldn't return bit patterns from outside the limits of the bitset.
-    }
+  { // test values bigger than can fit into the bitset
+    const unsigned long val  = 0x5AFFFFA5UL;
+    const bool canFit        = N < sizeof(unsigned long) * CHAR_BIT;
+    const unsigned long mask = canFit ? (1UL << (canFit ? N : 0)) - 1 : (unsigned long)(-1); // avoid compiler warnings
+    std::bitset<N> v(val);
+    assert(v.to_ulong() == (val & mask)); // we shouldn't return bit patterns from outside the limits of the bitset.
+  }
 }
 
 TEST_CONSTEXPR_CXX23 bool test() {
@@ -58,6 +59,20 @@ TEST_CONSTEXPR_CXX23 bool test() {
   test_to_ulong<65>();
   test_to_ulong<1000>();
 
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    // bitset has true bits beyond the size of unsigned long
+    std::bitset<std::numeric_limits<unsigned long>::digits + 1> q(0);
+    q.flip();
+    try {
+      q.to_ulong(); // throws
+      assert(false);
+    } catch (const std::overflow_error&) {
+      // expected
+    } catch (...) {
+      assert(false);
+    }
+  }
+
   return true;
 }
 



More information about the libcxx-commits mailing list