On Thu, 25 Jun 2026 at 14:02, Tomasz Kaminski <[email protected]> wrote:
>
>
>
>
> On Thu, Jun 25, 2026 at 2:51 PM Jonathan Wakely <[email protected]> wrote:
>>
>> On Thu, 25 Jun 2026 at 13:31, Tomasz Kamiński <[email protected]> wrote:
>> >
>> > This implements remaining changes from P3612R1 Harmonize proxy-reference
>> > operations (LWG 3638 and 4187).
>> >
>> > As the const-assigment operator in bitset::reference (from LWG4187)
>> > is used by range concepts (std::indirectly_writable) to recognize
>> > iterator returning it by value as proxy iterator (see range_proxy.cc) test,
>> > this change is backported to C++23. This puts it inline with vector<bool>
>> > reference and other proxy type, for which the coresponding assigment
>> > operator where added by P2321 in C++20 and implemented in r13-2159-g72886f.
>> >
>> > Similary, a swap overloads accepting bitset::reference by value and bool&,
>> > are necessary for ranges::swap and ranges::iter_swap to work correctly,
>> > so they should also backported. This patch follows the approach from
>> > resolution of LWG3638 from r12-5311-g59434931fb658f, and backports the
>> > overloads to C++11. This harmonizes the operations on this two proxy
>> > types (per paper title). Corresponding test are added to both classes.
>> >
>> > The deprecation warning for static vector<bool>::swap is added sinc C++26.
>> > The text in _GLIBCXX26_DEPRECATED_SUGGEST leads to following message:
>> >   'static constexpr void std::vector<bool, _Alloc>::swap(reference, 
>> > reference)
>> >   [with... ]' is deprecated: use 'swap' invoked via ADL or 
>> > 'std::ranges::swap'
>> >   instead
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> >         * include/bits/stl_bvector.h: Add _GLIBCXX_RESOLVE_LIB_DEFECTS
>> >         comment for 3638.
>> >         (vector<bool, _Alloc>::swap): Add deprected attribute via
>> >         _GLIBCXX26_DEPRECATED_SUGGEST.
>> >         * include/std/bitset (bitset::operator=(bool) const)
>> >         [__cplusplus > 202002]: Define.
>> >         (bistset::reference::swap) [__cplusplus >= 201103L]: Define.
>> >         * testsuite/20_util/bitset/access/range_proxy.cc: New test.
>> >         * testsuite/20_util/bitset/access/ref_swap.cc: New test.
>> >         * 
>> > testsuite/23_containers/vector/bool/element_access/range_proxy.cc:
>> >         New test.
>> >         * testsuite/23_containers/vector/bool/element_access/ref_swap.cc:
>> >         New test.
>> >         * testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
>> >         Checkfor deprecated warning on static swap.
>> > ---
>> > Do you agree with my backport choice for swap? I think the minimum is
>> > since C++23.
>>
>> I don't remember why I chose C++11 for the swap overloads for
>> vector<bool>::reference, but being consistent with that makes sense.
>>
>> >
>> > Testing on x86_64-linux. *bitset* and *vector/bool* test already passed
>> > in all standard modes. OK for trunk?
>> >
>> >  libstdc++-v3/include/bits/stl_bvector.h       |  4 +
>> >  libstdc++-v3/include/std/bitset               | 43 +++++++++
>> >  .../20_util/bitset/access/range_proxy.cc      | 94 +++++++++++++++++++
>> >  .../20_util/bitset/access/ref_swap.cc         | 28 ++++++
>> >  .../vector/bool/element_access/range_proxy.cc | 62 ++++++++++++
>> >  .../vector/bool/element_access/ref_swap.cc    | 38 ++++++++
>> >  .../vector/bool/modifiers/swap/constexpr.cc   |  2 +-
>> >  7 files changed, 270 insertions(+), 1 deletion(-)
>> >  create mode 100644 
>> > libstdc++-v3/testsuite/20_util/bitset/access/range_proxy.cc
>> >  create mode 100644 
>> > libstdc++-v3/testsuite/20_util/bitset/access/ref_swap.cc
>> >  create mode 100644 
>> > libstdc++-v3/testsuite/23_containers/vector/bool/element_access/range_proxy.cc
>> >  create mode 100644 
>> > libstdc++-v3/testsuite/23_containers/vector/bool/element_access/ref_swap.cc
>> >
>> > diff --git a/libstdc++-v3/include/bits/stl_bvector.h 
>> > b/libstdc++-v3/include/bits/stl_bvector.h
>> > index f190d1be5ce..0637e687cbb 100644
>> > --- a/libstdc++-v3/include/bits/stl_bvector.h
>> > +++ b/libstdc++-v3/include/bits/stl_bvector.h
>> > @@ -149,6 +149,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>> >      { *_M_p ^= _M_mask; }
>> >
>> >  #if __cplusplus >= 201103L
>> > +    // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > +    // 3638. vector<bool>::swap(reference, reference) is useless
>> > +
>> >      _GLIBCXX20_CONSTEXPR
>> >      friend void
>> >      swap(_Bit_reference __x, _Bit_reference __y) noexcept
>> > @@ -1266,6 +1269,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>> >        }
>> >
>> >        // [23.2.5]/1, third-to-last entry in synopsis listing
>> > +      _GLIBCXX26_DEPRECATED_SUGGEST("swap' invoked via ADL or 
>> > 'std::ranges::swap")
>> >        _GLIBCXX20_CONSTEXPR
>> >        static void
>> >        swap(reference __x, reference __y) _GLIBCXX_NOEXCEPT
>> > diff --git a/libstdc++-v3/include/std/bitset 
>> > b/libstdc++-v3/include/std/bitset
>> > index a8cb337f4b1..a5822319b90 100644
>> > --- a/libstdc++-v3/include/std/bitset
>> > +++ b/libstdc++-v3/include/std/bitset
>> > @@ -908,6 +908,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>> >           return *this;
>> >         }
>> >
>> > +#if __cplusplus > 202002L
>>
>> Should we use __glibcxx_ranges_zip here? That's the macro for P2321
>> which is what made the const-assignable changes that motivate this
>> change.
>
> This is matching check used for vector<bool>::reference from  r13-2159-g72886f
> (__cplusplus > 202002L), so I want for consistency.

All the #if checks in that commit used 202002 but we later changed
most of them to to use the feature test macro, in
r14-8253-gae8581ea5c525b
Maybe we should have changed vector<bool>::reference at the same time.

OK, we have the RESOLVE_LIB_DEFECTS comment to explain why the
const-assignment is present, and that issue refers to P2321 so that's
good enough.

OK for trunk.


> Could change all of them
> as separate commit. On the other hand, this is not strictly related to 
> zip_view,
> as people could write they own references.
>
> I have wondered if the "fixes" for proxies shouldn't actually be backported
> to C++20. so we support user-provided zip-views in C++20. But touching a tuple
> is always scary.

I don't want to make that change, it wasn't a DR it was a C++23
feature. User-provided zip views just can't use std::tuple as their
proxy in C++20.

>>
>> If it's changed here it should be changed in the range_proxy.cc test too.
>
> That does not work nice if we ever replace includes with modules, as we would
> need to include <version>.

That's the case for other tests already. In some cases the feature
test macro is the right thing to check in the test, because it might
depend on other conditions not only the __cplusplus value. So we might
want to add <version> to affected tests, or just run the tests with
-include version



>>
>>
>> > +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > +       // 4187. bitset::reference should be const-assignable
>> > +       constexpr const reference&
>> > +       operator=(bool __x) const noexcept
>> > +       {
>> > +         if (__x)
>> > +           *_M_wp |= _Base::_S_maskbit(_M_bpos);
>> > +         else
>> > +           *_M_wp &= ~_Base::_S_maskbit(_M_bpos);
>> > +         return *this;
>> > +       }
>> > +#endif // C++23
>> > +
>> >         // For b[i] = b[__j];
>> >         _GLIBCXX23_CONSTEXPR
>> >         reference&
>> > @@ -939,6 +953,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>> >           *_M_wp ^= _Base::_S_maskbit(_M_bpos);
>> >           return *this;
>> >         }
>> > +
>> > +#if __cplusplus >= 201103L
>>
>> Using 201103 here matches the condition for the
>> vector<bool>::reference swap overloads, good.
>>
>> > +       _GLIBCXX23_CONSTEXPR
>> > +       friend void
>> > +       swap(reference __x, reference __y) noexcept
>> > +       {
>> > +         bool __tmp = __x;
>> > +         __x = __y;
>> > +         __y = __tmp;
>> > +       }
>> > +
>> > +       _GLIBCXX23_CONSTEXPR
>> > +       friend void
>> > +       swap(reference __x, bool& __y) noexcept
>> > +       {
>> > +         bool __tmp = __x;
>> > +         __x = __y;
>> > +         __y = __tmp;
>> > +       }
>> > +
>> > +       _GLIBCXX23_CONSTEXPR
>> > +       friend void
>> > +       swap(bool& __x, reference __y) noexcept
>> > +       {
>> > +         bool __tmp = __x;
>> > +         __x = __y;
>> > +         __y = __tmp;
>> > +       }
>> > +#endif
>> >        };
>> >        friend class reference;
>> >
>> > diff --git a/libstdc++-v3/testsuite/20_util/bitset/access/range_proxy.cc 
>> > b/libstdc++-v3/testsuite/20_util/bitset/access/range_proxy.cc
>> > new file mode 100644
>> > index 00000000000..9eac384ce44
>> > --- /dev/null
>> > +++ b/libstdc++-v3/testsuite/20_util/bitset/access/range_proxy.cc
>> > @@ -0,0 +1,94 @@
>> > +// { dg-do run { target c++20 } }
>> > +
>> > +#include <bitset>
>> > +#include <concepts>
>> > +#include <iterator>
>> > +#include <testsuite_hooks.h>
>> > +
>> > +void
>> > +test_swap()
>> > +{
>> > +  std::bitset<2> v("01");
>> > +  std::ranges::swap(v[0], v[1]);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true;
>> > +  std::ranges::swap(v[0], b);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  std::ranges::swap(b, v[1]);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +template<size_t N>
>> > +struct bitset_iterator
>> > +{
>> > +  using value_type = bool;
>> > +  using reference = std::bitset<2>::reference;
>> > +  using iterator_category = std::forward_iterator_tag;
>> > +  using difference_type = std::ptrdiff_t;
>> > +
>> > +  bitset_iterator() = default;
>> > +  bitset_iterator(std::bitset<N>& c) noexcept : cont(&c) {}
>> > +
>> > +  reference operator*() const noexcept
>> > +  { return (*cont)[pos]; }
>> > +
>> > +  bitset_iterator& operator++() {
>> > +   ++pos;
>> > +   return *this;
>> > +  }
>> > +
>> > +  bitset_iterator operator++(int) {
>> > +    auto tmp = *this;
>> > +    ++pos;
>> > +    return *this;
>> > +  };
>> > +
>> > +  friend bool operator==(bitset_iterator, bitset_iterator) = default;
>> > +
>> > +private:
>> > +  std::bitset<N>* cont = nullptr;
>> > +  size_t pos = 0;
>> > +};
>> > +
>> > +void
>> > +test_iter_swap()
>> > +{
>> > +  std::bitset<2> v("01");
>> > +  auto it1 = bitset_iterator<2>(v);
>> > +  auto it2 = std::ranges::next(it1);
>> > +  std::ranges::iter_swap(it1, it2);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true, *p = &b;
>> > +  std::ranges::iter_swap(it1, p);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  std::ranges::iter_swap(p, it2);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +#if __cplusplus > 202002L
>> > +static_assert( std::indirectly_writable<bitset_iterator<2>, bool> );
>> > +static_assert( std::indirectly_writable<bitset_iterator<2>,
>> > +                                       std::bitset<2>::reference> );
>> > +
>> > +#else
>> > +static_assert( !std::indirectly_writable<bitset_iterator<2>, bool> );
>> > +static_assert( !std::indirectly_writable<bitset_iterator<2>,
>> > +                                        std::bitset<2>::reference> );
>> > +#endif
>> > +
>> > +int
>> > +main()
>> > +{
>> > +  test_swap();
>> > +  test_iter_swap();
>> > +}
>> > diff --git a/libstdc++-v3/testsuite/20_util/bitset/access/ref_swap.cc 
>> > b/libstdc++-v3/testsuite/20_util/bitset/access/ref_swap.cc
>> > new file mode 100644
>> > index 00000000000..1d8e3c1bf49
>> > --- /dev/null
>> > +++ b/libstdc++-v3/testsuite/20_util/bitset/access/ref_swap.cc
>> > @@ -0,0 +1,28 @@
>> > +// { dg-do run { target c++11 } }
>> > +
>> > +#include <bitset>
>> > +#include <testsuite_hooks.h>
>> > +
>> > +void
>> > +test_friend()
>> > +{
>> > +  std::bitset<2> v("01");
>> > +  swap(v[0], v[1]);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true;
>> > +  swap(v[0], b);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  swap(b, v[1]);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +int
>> > +main()
>> > +{
>> > +  test_friend();
>> > +}
>> > diff --git 
>> > a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/range_proxy.cc
>> >  
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/range_proxy.cc
>> > new file mode 100644
>> > index 00000000000..075132034f1
>> > --- /dev/null
>> > +++ 
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/range_proxy.cc
>> > @@ -0,0 +1,62 @@
>> > +// { dg-do run { target c++20 } }
>> > +
>> > +#include <vector>
>> > +#include <concepts>
>> > +#include <iterator>
>> > +#include <testsuite_hooks.h>
>> > +
>> > +void
>> > +test_swap()
>> > +{
>> > +  std::vector<bool> v{true, false};
>> > +  std::ranges::swap(v[0], v[1]);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true;
>> > +  std::ranges::swap(v[0], b);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  std::ranges::swap(b, v[1]);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +void
>> > +test_iter_swap()
>> > +{
>> > +  std::vector<bool> v{true, false};
>> > +  auto it1 = v.begin();
>> > +  auto it2 = std::ranges::next(it1);
>> > +  std::ranges::iter_swap(it1, it2);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true, *p = &b;
>> > +  std::ranges::iter_swap(it1, p);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  std::ranges::iter_swap(p, it2);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +#if __cplusplus > 202002L
>> > +static_assert( std::indirectly_writable<std::vector<bool>::iterator, 
>> > bool> );
>> > +static_assert( std::indirectly_writable<std::vector<bool>::iterator,
>> > +                                       std::vector<bool>::reference> );
>> > +
>> > +#else
>> > +static_assert( !std::indirectly_writable<std::vector<bool>::iterator, 
>> > bool> );
>> > +static_assert( !std::indirectly_writable<std::vector<bool>::iterator,
>> > +                                        std::vector<bool>::reference> );
>> > +#endif
>> > +
>> > +int
>> > +main()
>> > +{
>> > +  test_swap();
>> > +  test_iter_swap();
>> > +}
>> > diff --git 
>> > a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/ref_swap.cc
>> >  
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/ref_swap.cc
>> > new file mode 100644
>> > index 00000000000..2221e3b03f0
>> > --- /dev/null
>> > +++ 
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/ref_swap.cc
>> > @@ -0,0 +1,38 @@
>> > +// { dg-do run { target c++11 } }
>> > +
>> > +#include <vector>
>> > +#include <testsuite_hooks.h>
>> > +
>> > +void
>> > +test_friend()
>> > +{
>> > +  std::vector<bool> v{true, false};
>> > +  swap(v[0], v[1]);
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +
>> > +  bool b = true;
>> > +  swap(v[0], b);
>> > +  VERIFY( v[0] == true );
>> > +  VERIFY( b == false );
>> > +
>> > +  swap(b, v[1]);
>> > +  VERIFY( v[1] == false );
>> > +  VERIFY( b == true );
>> > +}
>> > +
>> > +void
>> > +test_static()
>> > +{
>> > +  std::vector<bool> v{true, false};
>> > +  std::vector<bool>::swap(v[0], v[1]); // { dg-warning "deprecated" 
>> > "::swap" { target c++26 } }
>> > +  VERIFY( v[0] == false );
>> > +  VERIFY( v[1] == true );
>> > +}
>> > +
>> > +int
>> > +main()
>> > +{
>> > +  test_friend();
>> > +  test_static();
>> > +}
>> > diff --git 
>> > a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
>> >  
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
>> > index d2a0218a109..1eb526800f7 100644
>> > --- 
>> > a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
>> > +++ 
>> > b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
>> > @@ -53,7 +53,7 @@ constexpr bool
>> >  test_reference_swap()
>> >  {
>> >    std::vector<bool> v1 = {true, false, true};
>> > -  std::vector<bool>::swap(v1[0], v1[1]);
>> > +  std::vector<bool>::swap(v1[0], v1[1]); // { dg-warning "deprecated" 
>> > "::swap" { target c++26 } }
>> >
>> >    VERIFY(v1[0] == false);
>> >    VERIFY(v1[1] == true);
>> > --
>> > 2.54.0
>> >
>>

Reply via email to