Skip to content

Conversation

@frederick-vs-ja
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja commented Oct 18, 2024

Currently, libc++'s bitset, forward_list, and list have non-conforming member typedef name base. The typedef is private, but can cause ambiguity in name lookup.

Some other classes in libc++ that are either implementation details or not precisely specified by the standard also have member typdef base. I think this can still be conforming.

Follows up #80706 and #111127.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner October 18, 2024 06:04
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 18, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 18, 2024

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

Changes

Currently, libc++'s bitset, forward_list, and list have non-conforming member typedef name base. The typedef is private, but can cause ambiguity in name lookup.

Some other classes in libc++ that are either implementation details or not precisely specified by the standard also have member typdef base. I think this can still be conforming.

Drive-by change: Using using typename __base:: to introduce member typedefs for short.

Follows up #80706 and #111127.


Patch is 50.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112843.diff

7 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/20.rst (+3-3)
  • (modified) libcxx/include/bitset (+26-26)
  • (modified) libcxx/include/forward_list (+57-52)
  • (modified) libcxx/include/list (+96-95)
  • (modified) libcxx/test/std/containers/sequences/forwardlist/types.pass.cpp (+18)
  • (modified) libcxx/test/std/containers/sequences/list/types.pass.cpp (+18)
  • (modified) libcxx/test/std/utilities/template.bitset/bitset.members/nonstdmem.uglified.compile.pass.cpp (+13-2)
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index abd6764579e52a..44912d2ddafac6 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -78,9 +78,9 @@ Deprecations and Removals
   supported as an extension anymore, please migrate any code that uses e.g. ``std::vector<const T>`` to be
   standards conforming.
 
-- Non-conforming member typedefs ``iterator`` and ``const_iterator`` of ``std::bitset`` are removed. Previously, they
-  were private but could cause ambiguity in name lookup. Code that expects such ambiguity will possibly not compile in
-  LLVM 20.
+- Non-conforming member typedefs ``base``, ``iterator`` and ``const_iterator`` of ``std::bitset``, and member typedef
+  ``base`` of ``std::forward_list`` and ``std::list`` are removed. Previously, they were private but could cause
+  ambiguity in name lookup. Code that expects such ambiguity will possibly not compile in LLVM 20.
 
 - The function ``__libcpp_verbose_abort()`` is now ``noexcept``, to match ``std::terminate()``. (The combination of
   ``noexcept`` and ``[[noreturn]]`` has special significance for function effects analysis.)
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index f90ceaab816cca..a66c670c215a54 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -612,15 +612,15 @@ class _LIBCPP_TEMPLATE_VIS bitset
     : private __bitset<_Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * CHAR_BIT) + 1, _Size> {
 public:
   static const unsigned __n_words = _Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * CHAR_BIT) + 1;
-  typedef __bitset<__n_words, _Size> base;
+  typedef __bitset<__n_words, _Size> __base;
 
 public:
-  typedef typename base::reference reference;
-  typedef typename base::const_reference const_reference;
+  using typename __base::reference;
+  using typename __base::const_reference;
 
   // 23.3.5.1 constructors:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bitset() _NOEXCEPT {}
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bitset(unsigned long long __v) _NOEXCEPT : base(__v) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bitset(unsigned long long __v) _NOEXCEPT : __base(__v) {}
   template <class _CharT, __enable_if_t<_IsCharLikeType<_CharT>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit bitset(
       const _CharT* __str,
@@ -681,11 +681,11 @@ public:
 
   // element access:
 #ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { return base::__make_ref(__p); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { return __base::__make_ref(__p); }
 #else
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference operator[](size_t __p) const { return base::__make_ref(__p); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference operator[](size_t __p) const { return __base::__make_ref(__p); }
 #endif
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) { return base::__make_ref(__p); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) { 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;
   template <class _CharT, class _Traits, class _Allocator>
@@ -726,10 +726,10 @@ private:
       _CharT __c   = __str[__mp - 1 - __i];
       (*this)[__i] = _Traits::eq(__c, __one);
     }
-    std::fill(base::__make_iter(__i), base::__make_iter(_Size), false);
+    std::fill(__base::__make_iter(__i), __base::__make_iter(_Size), false);
   }
 
-  _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT { return base::__hash_code(); }
+  _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT { return __base::__hash_code(); }
 
   friend struct hash<bitset>;
 };
@@ -737,43 +737,43 @@ private:
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>&
 bitset<_Size>::operator&=(const bitset& __rhs) _NOEXCEPT {
-  base::operator&=(__rhs);
+  __base::operator&=(__rhs);
   return *this;
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>&
 bitset<_Size>::operator|=(const bitset& __rhs) _NOEXCEPT {
-  base::operator|=(__rhs);
+  __base::operator|=(__rhs);
   return *this;
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>&
 bitset<_Size>::operator^=(const bitset& __rhs) _NOEXCEPT {
-  base::operator^=(__rhs);
+  __base::operator^=(__rhs);
   return *this;
 }
 
 template <size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::operator<<=(size_t __pos) _NOEXCEPT {
   __pos = std::min(__pos, _Size);
-  std::copy_backward(base::__make_iter(0), base::__make_iter(_Size - __pos), base::__make_iter(_Size));
-  std::fill_n(base::__make_iter(0), __pos, false);
+  std::copy_backward(__base::__make_iter(0), __base::__make_iter(_Size - __pos), __base::__make_iter(_Size));
+  std::fill_n(__base::__make_iter(0), __pos, false);
   return *this;
 }
 
 template <size_t _Size>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::operator>>=(size_t __pos) _NOEXCEPT {
   __pos = std::min(__pos, _Size);
-  std::copy(base::__make_iter(__pos), base::__make_iter(_Size), base::__make_iter(0));
-  std::fill_n(base::__make_iter(_Size - __pos), __pos, false);
+  std::copy(__base::__make_iter(__pos), __base::__make_iter(_Size), __base::__make_iter(0));
+  std::fill_n(__base::__make_iter(_Size - __pos), __pos, false);
   return *this;
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::set() _NOEXCEPT {
-  std::fill_n(base::__make_iter(0), _Size, true);
+  std::fill_n(__base::__make_iter(0), _Size, true);
   return *this;
 }
 
@@ -788,7 +788,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::reset() _NOEXCEPT {
-  std::fill_n(base::__make_iter(0), _Size, false);
+  std::fill_n(__base::__make_iter(0), _Size, false);
   return *this;
 }
 
@@ -810,7 +810,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> bitset<
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>::flip() _NOEXCEPT {
-  base::flip();
+  __base::flip();
   return *this;
 }
 
@@ -819,19 +819,19 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>& bitset<_Size>
   if (__pos >= _Size)
     __throw_out_of_range("bitset flip argument out of range");
 
-  reference __r = base::__make_ref(__pos);
+  reference __r = __base::__make_ref(__pos);
   __r           = ~__r;
   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();
+  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();
+  return __base::to_ullong();
 }
 
 template <size_t _Size>
@@ -868,13 +868,13 @@ bitset<_Size>::to_string(char __zero, char __one) const {
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t bitset<_Size>::count() const _NOEXCEPT {
-  return static_cast<size_t>(std::count(base::__make_iter(0), base::__make_iter(_Size), true));
+  return static_cast<size_t>(std::count(__base::__make_iter(0), __base::__make_iter(_Size), true));
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool
 bitset<_Size>::operator==(const bitset& __rhs) const _NOEXCEPT {
-  return std::equal(base::__make_iter(0), base::__make_iter(_Size), __rhs.__make_iter(0));
+  return std::equal(__base::__make_iter(0), __base::__make_iter(_Size), __rhs.__make_iter(0));
 }
 
 #if _LIBCPP_STD_VER <= 17
@@ -896,12 +896,12 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::test(siz
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::all() const _NOEXCEPT {
-  return base::all();
+  return __base::all();
 }
 
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::any() const _NOEXCEPT {
-  return base::any();
+  return __base::any();
 }
 
 template <size_t _Size>
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index d3262fb8eaed1f..5f28f9a83048c7 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -640,12 +640,12 @@ void __forward_list_base<_Tp, _Alloc>::clear() _NOEXCEPT {
 
 template <class _Tp, class _Alloc /*= allocator<_Tp>*/>
 class _LIBCPP_TEMPLATE_VIS forward_list : private __forward_list_base<_Tp, _Alloc> {
-  typedef __forward_list_base<_Tp, _Alloc> base;
-  typedef typename base::__node_allocator __node_allocator;
-  typedef typename base::__node_type __node_type;
-  typedef typename base::__node_traits __node_traits;
-  typedef typename base::__node_pointer __node_pointer;
-  typedef typename base::__begin_node_pointer __begin_node_pointer;
+  typedef __forward_list_base<_Tp, _Alloc> __base;
+  using typename __base::__begin_node_pointer;
+  using typename __base::__node_allocator;
+  using typename __base::__node_pointer;
+  using typename __base::__node_traits;
+  using typename __base::__node_type;
 
 public:
   typedef _Tp value_type;
@@ -666,8 +666,8 @@ public:
   typedef typename allocator_traits<allocator_type>::size_type size_type;
   typedef typename allocator_traits<allocator_type>::difference_type difference_type;
 
-  typedef typename base::iterator iterator;
-  typedef typename base::const_iterator const_iterator;
+  using typename __base::const_iterator;
+  using typename __base::iterator;
 #if _LIBCPP_STD_VER >= 20
   typedef size_type __remove_return_type;
 #else
@@ -684,7 +684,7 @@ public:
   _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v);
 
   template <__enable_if_t<__is_allocator<_Alloc>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v, const allocator_type& __a) : base(__a) {
+  _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v, const allocator_type& __a) : __base(__a) {
     insert_after(cbefore_begin(), __n, __v);
   }
 
@@ -697,7 +697,7 @@ public:
 #if _LIBCPP_STD_VER >= 23
   template <_ContainerCompatibleRange<_Tp> _Range>
   _LIBCPP_HIDE_FROM_ABI forward_list(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
-      : base(__a) {
+      : __base(__a) {
     prepend_range(std::forward<_Range>(__range));
   }
 #endif
@@ -708,8 +708,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI forward_list& operator=(const forward_list& __x);
 
 #ifndef _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI forward_list(forward_list&& __x) noexcept(is_nothrow_move_constructible<base>::value)
-      : base(std::move(__x)) {}
+  _LIBCPP_HIDE_FROM_ABI forward_list(forward_list&& __x) noexcept(is_nothrow_move_constructible<__base>::value)
+      : __base(std::move(__x)) {}
   _LIBCPP_HIDE_FROM_ABI forward_list(forward_list&& __x, const __type_identity_t<allocator_type>& __a);
 
   _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list<value_type> __il);
@@ -738,35 +738,37 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v);
 
-  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(base::__alloc()); }
+  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__base::__alloc()); }
 
-  _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(base::__before_begin()->__next_); }
+  _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__base::__before_begin()->__next_); }
   _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
-    return const_iterator(base::__before_begin()->__next_);
+    return const_iterator(__base::__before_begin()->__next_);
   }
   _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return iterator(nullptr); }
   _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return const_iterator(nullptr); }
 
   _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT {
-    return const_iterator(base::__before_begin()->__next_);
+    return const_iterator(__base::__before_begin()->__next_);
   }
   _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return const_iterator(nullptr); }
 
-  _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { return iterator(base::__before_begin()); }
-  _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT { return const_iterator(base::__before_begin()); }
+  _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { return iterator(__base::__before_begin()); }
+  _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT {
+    return const_iterator(__base::__before_begin());
+  }
   _LIBCPP_HIDE_FROM_ABI const_iterator cbefore_begin() const _NOEXCEPT {
-    return const_iterator(base::__before_begin());
+    return const_iterator(__base::__before_begin());
   }
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT {
-    return base::__before_begin()->__next_ == nullptr;
+    return __base::__before_begin()->__next_ == nullptr;
   }
   _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
-    return std::min<size_type>(__node_traits::max_size(base::__alloc()), numeric_limits<difference_type>::max());
+    return std::min<size_type>(__node_traits::max_size(__base::__alloc()), numeric_limits<difference_type>::max());
   }
 
-  _LIBCPP_HIDE_FROM_ABI reference front() { return base::__before_begin()->__next_->__get_value(); }
-  _LIBCPP_HIDE_FROM_ABI const_reference front() const { return base::__before_begin()->__next_->__get_value(); }
+  _LIBCPP_HIDE_FROM_ABI reference front() { return __base::__before_begin()->__next_->__get_value(); }
+  _LIBCPP_HIDE_FROM_ABI const_reference front() const { return __base::__before_begin()->__next_->__get_value(); }
 
 #ifndef _LIBCPP_CXX03_LANG
 #  if _LIBCPP_STD_VER >= 17
@@ -823,12 +825,12 @@ public:
       _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__node_allocator>)
 #endif
   {
-    base::swap(__x);
+    __base::swap(__x);
   }
 
   _LIBCPP_HIDE_FROM_ABI void resize(size_type __n);
   _LIBCPP_HIDE_FROM_ABI void resize(size_type __n, const value_type& __v);
-  _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { base::clear(); }
+  _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __base::clear(); }
 
   _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x);
   _LIBCPP_HIDE_FROM_ABI void splice_after(const_iterator __p, forward_list&& __x, const_iterator __i);
@@ -899,12 +901,12 @@ forward_list(from_range_t, _Range&&, _Alloc = _Alloc()) -> forward_list<ranges::
 #endif
 
 template <class _Tp, class _Alloc>
-inline forward_list<_Tp, _Alloc>::forward_list(const allocator_type& __a) : base(__a) {}
+inline forward_list<_Tp, _Alloc>::forward_list(const allocator_type& __a) : __base(__a) {}
 
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(size_type __n) {
   if (__n > 0) {
-    for (__begin_node_pointer __p = base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) {
+    for (__begin_node_pointer __p = __base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) {
       __p->__next_ = this->__create_node(/* next = */ nullptr);
     }
   }
@@ -912,9 +914,9 @@ forward_list<_Tp, _Alloc>::forward_list(size_type __n) {
 
 #if _LIBCPP_STD_VER >= 14
 template <class _Tp, class _Alloc>
-forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __base_alloc) : base(__base_alloc) {
+forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __base_alloc) : __base(__base_alloc) {
   if (__n > 0) {
-    for (__begin_node_pointer __p = base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) {
+    for (__begin_node_pointer __p = __base::__before_begin(); __n > 0; --__n, __p = __p->__next_as_begin()) {
       __p->__next_ = this->__create_node(/* next = */ nullptr);
     }
   }
@@ -934,26 +936,27 @@ forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l)
 
 template <class _Tp, class _Alloc>
 template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> >
-forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l, const allocator_type& __a) : base(__a) {
+forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l, const allocator_type& __a)
+    : __base(__a) {
   insert_after(cbefore_begin(), __f, __l);
 }
 
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x)
-    : base(__node_traits::select_on_container_copy_construction(__x.__alloc())) {
+    : __base(__node_traits::select_on_container_copy_construction(__x.__alloc())) {
   insert_after(cbefore_begin(), __x.begin(), __x.end());
 }
 
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(const forward_list& __x, const __type_identity_t<allocator_type>& __a)
-    : base(__a) {
+    : __base(__a) {
   insert_after(cbefore_begin(), __x.begin(), __x.end());
 }
 
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(const forward_list& __x) {
   if (this != std::addressof(__x)) {
-    base::__copy_assign_alloc(__x);
+    __base::__copy_assign_alloc(__x);
     assign(__x.begin(), __x.end());
   }
   return *this;
@@ -962,8 +965,8 @@ forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(const forward_li
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Tp, class _Alloc>
 forward_list<_Tp, _Alloc>::forward_list(forward_list&& __x, const __type_identity_t<allocator_type>& __a)
-    : base(std::move(__x), __a) {
-  if (base::__alloc() != __x.__alloc()) {
+    : __base(std::move(__x), __a) {
+  if (__base::__alloc() != __x.__alloc()) {
     typedef move_iterator<iterator> _Ip;
     insert_after(cbefore_begin(), _Ip(__x.begin()), _Ip(__x.end()));
   }
@@ -975,7 +978,7 @@ forward_list<_Tp, _Alloc>::forward_list(initializer_list<value_type> __il) {
 }
 
 template <class _Tp, class _Alloc>
-forward_list<_Tp, _Alloc>::forward_list(initializer_list<value_type> __il, const allocator_type& __a) : base(__a) {
+forward_list<_Tp, _Alloc>::forward_list(initializer_list<value_type> __il, const allocator_type& __a) : __base(__a) {
   insert_after(cbefore_begin(), __il.begin(), __il.end());
 }
 
@@ -983,14 +986,14 @@ template <class _Tp, class _Alloc>
 void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, true_type)
     _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) {
   clear();
-  base::__move_assign_alloc(__x);
-  base::__before_begin()->__next_ = __x.__before_begin()->__next_;
-  __x.__before_begin()->__next_   = nullptr;
+  __base::__move_assign_alloc(__x);
+  __base::__before_begin()->__next_ = __x.__before_begin()->__next_;
+  __x.__before_begin()->__next_     = nullptr;
 }
 
 template <class _Tp, class _Alloc>
 void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) {
-  if (base::__alloc() == __x.__alloc())
+  if (__base::__alloc() == __x.__alloc())
     __move_assign(__x, true_type());
   else {
     typedef move_iterator<iterator> _Ip;
@@ -1061,29 +1064,30 @@ typename forward_list<_Tp, _Alloc>::reference
 void
 #  endif
 forward_list<_Tp, _Alloc>::emplace_front(_Args&&... __args) {
-  base::__before_begin()->__next_ =
-      this->__create_node(/* next = */ base::__before_begin()->__next_, std::forward<_Args>(__args)...);
+  __base::__before_begin()->__next_ =
+      this->__create_node(/* next = */ __base::__before_begin()->__next_, std::forward<_Args>(__args)...);
 #  if _LIBCPP_STD_VER >= 17
-  return base::__before_begin()->__next_->__get_value();
+  return __base::__before_begin()->__next_->__get_value();
 #  endif
 }
 
 template <class _Tp, class _Alloc>
 void fo...
[truncated]

@github-actions
Copy link

github-actions bot commented Oct 18, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@frederick-vs-ja frederick-vs-ja force-pushed the __uglify-member-base branch 2 times, most recently from 3658fd2 to 0c84981 Compare October 18, 2024 06:26
Currently, libc++'s `bitset`, `forward_list`, and `list` have
non-conforming member typedef name `base`. The typedef is private, but
can cause ambiguity in name lookup.

Some other classes in libc++ that are either implementation details or
not precisely specified by the standard also have member typdef `base`.
I think this can still be conforming.
@frederick-vs-ja frederick-vs-ja merged commit 397707f into llvm:main Oct 18, 2024
68 checks passed
@frederick-vs-ja frederick-vs-ja deleted the __uglify-member-base branch October 18, 2024 15:27
frederick-vs-ja pushed a commit that referenced this pull request Jan 9, 2025
…#121620)

According to
[[template.bitset.general]](https://eel.is/c++draft/template.bitset.general),
`std::bitset` is supposed to have only
one (public) member typedef, `reference`. However, libc++'s
implementation of `std::bitset` offers more that that. Specifically, it
offers a public typedef `const_reference` and two private typedefs
`size_type` and `difference_type`. These non-standard member typedefs,
despite being private, can cause potential ambiguities in name lookup in
user-defined classes, as demonstrated in issue #121618.

Fixing the public member typedef `const_reference` is straightforward:
we can simply replace it with an `__ugly_name` such as
`__const_reference`. However, fixing the private member typedefs
`size_type` and `difference_type` is not so straightforward as they are
required by the `__bit_iterator` class and the corresponding algorithms
optimized for `__bit_iterator`s (e.g., `ranges::fill`).
 
This PR fixes the member typedef `const_reference` by using uglified
name for it. Further work will be undertaken to address `size_type` and
`difference_type`.

Follows up #80706, #111127, and #112843,
philnik777 added a commit to philnik777/llvm-project that referenced this pull request Aug 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants