Skip to content

Commit 06673a9

Browse files
authored
[libc++] Uglify non-standard member typedef const_reference in bitset (#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,
1 parent f88ef1b commit 06673a9

File tree

4 files changed

+42
-27
lines changed

4 files changed

+42
-27
lines changed

libcxx/docs/ReleaseNotes/20.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,10 @@ Deprecations and Removals
125125
supported as an extension anymore, please migrate any code that uses e.g. ``std::vector<const T>`` to be
126126
standards conforming.
127127

128-
- Non-conforming member typedefs ``base``, ``iterator`` and ``const_iterator`` of ``std::bitset``, and member typedef
129-
``base`` of ``std::forward_list`` and ``std::list`` are removed. Previously, they were private but could cause
130-
ambiguity in name lookup. Code that expects such ambiguity will possibly not compile in LLVM 20.
128+
- Non-conforming member typedefs ``base``, ``iterator``, ``const_iterator``, and ``const_reference`` of ``std::bitset``,
129+
and member typedef ``base`` of ``std::forward_list`` and ``std::list`` are removed. Previously, these member typedefs
130+
(except ``const_reference``) were private but could cause ambiguity in name lookup. Code that expects such ambiguity
131+
will possibly not compile in LLVM 20.
131132

132133
- The function ``__libcpp_verbose_abort()`` is now ``noexcept``, to match ``std::terminate()``. (The combination of
133134
``noexcept`` and ``[[noreturn]]`` has special significance for function effects analysis.) For backwards compatibility,

libcxx/include/bitset

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ protected:
189189
__storage_type __first_[_N_words];
190190

191191
typedef __bit_reference<__bitset> reference;
192-
typedef __bit_const_reference<__bitset> const_reference;
192+
typedef __bit_const_reference<__bitset> __const_reference;
193193
typedef __bit_iterator<__bitset, false> __iterator;
194194
typedef __bit_iterator<__bitset, true> __const_iterator;
195195

@@ -199,8 +199,8 @@ protected:
199199
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference __make_ref(size_t __pos) _NOEXCEPT {
200200
return reference(__first_ + __pos / __bits_per_word, __storage_type(1) << __pos % __bits_per_word);
201201
}
202-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __make_ref(size_t __pos) const _NOEXCEPT {
203-
return const_reference(__first_ + __pos / __bits_per_word, __storage_type(1) << __pos % __bits_per_word);
202+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference __make_ref(size_t __pos) const _NOEXCEPT {
203+
return __const_reference(__first_ + __pos / __bits_per_word, __storage_type(1) << __pos % __bits_per_word);
204204
}
205205
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __iterator __make_iter(size_t __pos) _NOEXCEPT {
206206
return __iterator(__first_ + __pos / __bits_per_word, __pos % __bits_per_word);
@@ -451,7 +451,7 @@ protected:
451451
__storage_type __first_;
452452

453453
typedef __bit_reference<__bitset> reference;
454-
typedef __bit_const_reference<__bitset> const_reference;
454+
typedef __bit_const_reference<__bitset> __const_reference;
455455
typedef __bit_iterator<__bitset, false> __iterator;
456456
typedef __bit_iterator<__bitset, true> __const_iterator;
457457

@@ -461,8 +461,8 @@ protected:
461461
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference __make_ref(size_t __pos) _NOEXCEPT {
462462
return reference(&__first_, __storage_type(1) << __pos);
463463
}
464-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __make_ref(size_t __pos) const _NOEXCEPT {
465-
return const_reference(&__first_, __storage_type(1) << __pos);
464+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference __make_ref(size_t __pos) const _NOEXCEPT {
465+
return __const_reference(&__first_, __storage_type(1) << __pos);
466466
}
467467
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __iterator __make_iter(size_t __pos) _NOEXCEPT {
468468
return __iterator(&__first_ + __pos / __bits_per_word, __pos % __bits_per_word);
@@ -566,7 +566,7 @@ protected:
566566
friend struct __bit_array<__bitset>;
567567

568568
typedef __bit_reference<__bitset> reference;
569-
typedef __bit_const_reference<__bitset> const_reference;
569+
typedef __bit_const_reference<__bitset> __const_reference;
570570
typedef __bit_iterator<__bitset, false> __iterator;
571571
typedef __bit_iterator<__bitset, true> __const_iterator;
572572

@@ -576,8 +576,8 @@ protected:
576576
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference __make_ref(size_t) _NOEXCEPT {
577577
return reference(nullptr, 1);
578578
}
579-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __make_ref(size_t) const _NOEXCEPT {
580-
return const_reference(nullptr, 1);
579+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference __make_ref(size_t) const _NOEXCEPT {
580+
return __const_reference(nullptr, 1);
581581
}
582582
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __iterator __make_iter(size_t) _NOEXCEPT {
583583
return __iterator(nullptr, 0);
@@ -619,7 +619,7 @@ public:
619619

620620
public:
621621
typedef typename __base::reference reference;
622-
typedef typename __base::const_reference const_reference;
622+
typedef typename __base::__const_reference __const_reference;
623623

624624
// 23.3.5.1 constructors:
625625
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bitset() _NOEXCEPT {}
@@ -689,7 +689,7 @@ public:
689689
return __base::__make_ref(__p);
690690
}
691691
# else
692-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference operator[](size_t __p) const {
692+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference operator[](size_t __p) const {
693693
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds");
694694
return __base::__make_ref(__p);
695695
}

libcxx/test/std/utilities/template.bitset/bitset.members/index_const.pass.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
// constexpr bool operator[](size_t pos) const; // constexpr since C++23
1010

11+
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
12+
1113
#include <bitset>
1214
#include <cassert>
1315
#include <cstddef>
@@ -18,17 +20,17 @@
1820

1921
template <std::size_t N>
2022
TEST_CONSTEXPR_CXX23 void test_index_const() {
21-
std::vector<std::bitset<N> > const cases = get_test_cases<N>();
22-
for (std::size_t c = 0; c != cases.size(); ++c) {
23-
std::bitset<N> const v = cases[c];
24-
if (v.size() > 0) {
25-
assert(v[N/2] == v.test(N/2));
26-
}
23+
std::vector<std::bitset<N> > const cases = get_test_cases<N>();
24+
for (std::size_t c = 0; c != cases.size(); ++c) {
25+
std::bitset<N> const v = cases[c];
26+
if (v.size() > 0) {
27+
assert(v[N / 2] == v.test(N / 2));
2728
}
29+
}
2830
#if !defined(_LIBCPP_VERSION) || defined(_LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL)
29-
ASSERT_SAME_TYPE(decltype(cases[0][0]), bool);
31+
ASSERT_SAME_TYPE(decltype(cases[0][0]), bool);
3032
#else
31-
ASSERT_SAME_TYPE(decltype(cases[0][0]), typename std::bitset<N>::const_reference);
33+
ASSERT_SAME_TYPE(decltype(cases[0][0]), typename std::bitset<N>::__const_reference);
3234
#endif
3335
}
3436

@@ -43,10 +45,10 @@ TEST_CONSTEXPR_CXX23 bool test() {
4345
test_index_const<65>();
4446

4547
std::bitset<1> set_;
46-
set_[0] = false;
48+
set_[0] = false;
4749
const auto& set = set_;
48-
auto b = set[0];
49-
set_[0] = true;
50+
auto b = set[0];
51+
set_[0] = true;
5052
#if !defined(_LIBCPP_VERSION) || defined(_LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL)
5153
assert(!b);
5254
#else

libcxx/test/std/utilities/template.bitset/bitset.members/nonstdmem.uglified.compile.pass.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

99
// <bitset>
1010

11-
// This test ensures that we don't use a non-uglified name 'iterator',
12-
// 'const_iterator', and 'base' in the implementation of bitset.
11+
// This test ensures that we don't use a non-uglified name 'base', 'iterator',
12+
// 'const_iterator', and `const_reference` in the implementation of bitset.
1313
//
1414
// See https://github.com/llvm/llvm-project/issues/111125.
15+
// See https://github.com/llvm/llvm-project/issues/121618.
1516

1617
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
1718

@@ -23,6 +24,7 @@ struct my_base {
2324
typedef int* iterator;
2425
typedef const int* const_iterator;
2526
typedef my_base base;
27+
typedef const int& const_reference;
2628
};
2729

2830
template <std::size_t N>
@@ -57,3 +59,13 @@ static_assert(std::is_same<my_derived<32>::base, my_base>::value, "");
5759
static_assert(std::is_same<my_derived<48>::base, my_base>::value, "");
5860
static_assert(std::is_same<my_derived<64>::base, my_base>::value, "");
5961
static_assert(std::is_same<my_derived<96>::base, my_base>::value, "");
62+
63+
static_assert(std::is_same<my_derived<0>::const_reference, const int&>::value, "");
64+
static_assert(std::is_same<my_derived<1>::const_reference, const int&>::value, "");
65+
static_assert(std::is_same<my_derived<8>::const_reference, const int&>::value, "");
66+
static_assert(std::is_same<my_derived<12>::const_reference, const int&>::value, "");
67+
static_assert(std::is_same<my_derived<16>::const_reference, const int&>::value, "");
68+
static_assert(std::is_same<my_derived<32>::const_reference, const int&>::value, "");
69+
static_assert(std::is_same<my_derived<48>::const_reference, const int&>::value, "");
70+
static_assert(std::is_same<my_derived<64>::const_reference, const int&>::value, "");
71+
static_assert(std::is_same<my_derived<96>::const_reference, const int&>::value, "");

0 commit comments

Comments
 (0)