[PATCH] PR libstdc++/92059 fix several bugs in tr2::dynamic_bitset

Jonathan Wakely jwakely@redhat.com
Fri Oct 11 15:33:00 GMT 2019


	PR libstdc++/92059
	* include/tr2/dynamic_bitset (__dynamic_bitset_base): Define all
	special member functions as defaulted. Add noexcept to most members.
	(__dynamic_bitset_base(size_t, unsigned long long, const _Alloc&)):
	Mask off unwanted bits in the __val parameter. Avoid undefined left
	shifts.
	(__dynamic_bitset_base::_M_assign): Remove.
	(__dynamic_bitset_base::_M_do_reset): Use std::fill.
	(__dynamic_bitset_base::_M_are_all_aux): Avoid integer promotion when
	block_type has lower rank than int.
	(dynamic_bitset): Add noexcept to most members. Use injected-class-name
	in return types and parameter types.
	(dynamic_bitset::_M_Nb): Add default member initializer.
	(dynamic_bitset(), dynamic_bitset(const dynamic_bitset&)): Define as
	defaulted.
	(dynamic_bitset(dynamic_bitset&&)): Clear source object after move.
	(dynamic_bitset::operator=(const dynamic_bitset&)): Define as
	defaulted.
	(dynamic_bitset::operator=(dynamic_bitset&&)): Add noexcept-specifier.
	Define without using swap, to propagate allocator correctly.
	(dynamic_bitset(const char*, const _Alloc&)): Use strlen.
	(dynamic_bitset::_M_do_sanitize, dynamic_bitset::_M_do_fill): Use
	casts to avoid unwanted integer promotions.
	(dynamic_bitset::_M_copy_from_ptr): Rearrange template parameters and
	add default template arguments and default argument to simplify usage.
	(dynamic_bitset::_M_copy_from_string): Adjust call to _M_copy_from_ptr.
	(operator==(const dynamic_bitset&, const dynamic_bitset&))
	(operator<(const dynamic_bitset&, const dynamic_bitset&)): Use _M_Nb.
	* include/tr2/dynamic_bitset.tcc (dynamic_bitset::_M_copy_from_ptr):
	Adjust template parameters to match declaration.
	* testsuite/tr2/dynamic_bitset/cmp.cc: New test.
	* testsuite/tr2/dynamic_bitset/cons.cc: New test.
	* testsuite/tr2/dynamic_bitset/copy.cc: New test.
	* testsuite/tr2/dynamic_bitset/move.cc: New test.
	* testsuite/tr2/dynamic_bitset/pr92059.cc: New test.

Tested x86_64-linux. Committed to trunk.

This seems worth backporting too, as the type is now no longer totally
broken (e.g. it is now copy constructible, and the move constructor no
longer breaks the class invariant).


-------------- next part --------------
commit 18ed132a6b119bc2c23078848a8981ba96067a15
Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Oct 11 15:29:55 2019 +0000

    PR libstdc++/92059 fix several bugs in tr2::dynamic_bitset
    
            PR libstdc++/92059
            * include/tr2/dynamic_bitset (__dynamic_bitset_base): Define all
            special member functions as defaulted. Add noexcept to most members.
            (__dynamic_bitset_base(size_t, unsigned long long, const _Alloc&)):
            Mask off unwanted bits in the __val parameter. Avoid undefined left
            shifts.
            (__dynamic_bitset_base::_M_assign): Remove.
            (__dynamic_bitset_base::_M_do_reset): Use std::fill.
            (__dynamic_bitset_base::_M_are_all_aux): Avoid integer promotion when
            block_type has lower rank than int.
            (dynamic_bitset): Add noexcept to most members. Use injected-class-name
            in return types and parameter types.
            (dynamic_bitset::_M_Nb): Add default member initializer.
            (dynamic_bitset(), dynamic_bitset(const dynamic_bitset&)): Define as
            defaulted.
            (dynamic_bitset(dynamic_bitset&&)): Clear source object after move.
            (dynamic_bitset::operator=(const dynamic_bitset&)): Define as
            defaulted.
            (dynamic_bitset::operator=(dynamic_bitset&&)): Add noexcept-specifier.
            Define without using swap, to propagate allocator correctly.
            (dynamic_bitset(const char*, const _Alloc&)): Use strlen.
            (dynamic_bitset::_M_do_sanitize, dynamic_bitset::_M_do_fill): Use
            casts to avoid unwanted integer promotions.
            (dynamic_bitset::_M_copy_from_ptr): Rearrange template parameters and
            add default template arguments and default argument to simplify usage.
            (dynamic_bitset::_M_copy_from_string): Adjust call to _M_copy_from_ptr.
            (operator==(const dynamic_bitset&, const dynamic_bitset&))
            (operator<(const dynamic_bitset&, const dynamic_bitset&)): Use _M_Nb.
            * include/tr2/dynamic_bitset.tcc (dynamic_bitset::_M_copy_from_ptr):
            Adjust template parameters to match declaration.
            * testsuite/tr2/dynamic_bitset/cmp.cc: New test.
            * testsuite/tr2/dynamic_bitset/cons.cc: New test.
            * testsuite/tr2/dynamic_bitset/copy.cc: New test.
            * testsuite/tr2/dynamic_bitset/move.cc: New test.
            * testsuite/tr2/dynamic_bitset/pr92059.cc: New test.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@276890 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git a/libstdc++-v3/include/tr2/dynamic_bitset b/libstdc++-v3/include/tr2/dynamic_bitset
index 434a4cc87ec..28c877c0484 100644
--- a/libstdc++-v3/include/tr2/dynamic_bitset
+++ b/libstdc++-v3/include/tr2/dynamic_bitset
@@ -34,10 +34,9 @@
 #include <limits>
 #include <vector>
 #include <string>
-#include <memory> // For std::allocator
-#include <bits/functexcept.h>   // For invalid_argument, out_of_range,
-				// overflow_error
-#include <iosfwd>
+#include <istream>
+#include <bits/functexcept.h>
+#include <bits/stl_algo.h>	// For fill
 #include <bits/cxxabi_forced.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -76,41 +75,48 @@ namespace tr2
       std::vector<block_type, allocator_type> _M_w;
 
       explicit
-      __dynamic_bitset_base(const allocator_type& __alloc = allocator_type())
+      __dynamic_bitset_base(const allocator_type& __alloc)
       : _M_w(__alloc)
       { }
 
-      explicit
-      __dynamic_bitset_base(__dynamic_bitset_base&& __b)
-      { this->_M_w.swap(__b._M_w); }
+      __dynamic_bitset_base() = default;
+      __dynamic_bitset_base(const __dynamic_bitset_base&) = default;
+      __dynamic_bitset_base(__dynamic_bitset_base&& __b) = default;
+      __dynamic_bitset_base& operator=(const __dynamic_bitset_base&) = default;
+      __dynamic_bitset_base& operator=(__dynamic_bitset_base&&) = default;
+      ~__dynamic_bitset_base() = default;
 
       explicit
       __dynamic_bitset_base(size_type __nbits, unsigned long long __val = 0ULL,
 			   const allocator_type& __alloc = allocator_type())
-      : _M_w(__nbits / _S_bits_per_block
-	     + (__nbits % _S_bits_per_block > 0),
-	     __val, __alloc)
+      : _M_w(__nbits / _S_bits_per_block + (__nbits % _S_bits_per_block > 0),
+	     block_type(0), __alloc)
       {
-	unsigned long long __mask = ~static_cast<block_type>(0);
-	size_t __n = std::min(this->_M_w.size(),
-			      sizeof(unsigned long long) / sizeof(block_type));
-	for (size_t __i = 0; __i < __n; ++__i)
+	if (__nbits < std::numeric_limits<decltype(__val)>::digits)
+	  __val &= ~(-1ULL << __nbits);
+	if (__val == 0)
+	  return;
+
+	if _GLIBCXX17_CONSTEXPR (sizeof(__val) == sizeof(block_type))
+	  _M_w[0] = __val;
+	else
 	  {
-	    this->_M_w[__i] = (__val & __mask) >> (__i * _S_bits_per_block);
-	    __mask <<= _S_bits_per_block;
+	    const size_t __n
+	      = std::min(_M_w.size(), sizeof(__val) / sizeof(block_type));
+	    for (size_t __i = 0; __val && __i < __n; ++__i)
+	      {
+		_M_w[__i] = static_cast<block_type>(__val);
+		__val >>= _S_bits_per_block;
+	      }
 	  }
       }
 
       void
-      _M_assign(const __dynamic_bitset_base& __b)
-      { this->_M_w = __b._M_w; }
-
-      void
-      _M_swap(__dynamic_bitset_base& __b)
+      _M_swap(__dynamic_bitset_base& __b) noexcept
       { this->_M_w.swap(__b._M_w); }
 
       void
-      _M_clear()
+      _M_clear() noexcept
       { this->_M_w.clear(); }
 
       void
@@ -129,7 +135,7 @@ namespace tr2
       }
 
       allocator_type
-      _M_get_allocator() const
+      _M_get_allocator() const noexcept
       { return this->_M_w.get_allocator(); }
 
       static size_type
@@ -149,23 +155,23 @@ namespace tr2
       { return (static_cast<block_type>(1)) << _S_whichbit(__pos); }
 
       block_type&
-      _M_getword(size_type __pos)
+      _M_getword(size_type __pos) noexcept
       { return this->_M_w[_S_whichword(__pos)]; }
 
       block_type
-      _M_getword(size_type __pos) const
+      _M_getword(size_type __pos) const noexcept
       { return this->_M_w[_S_whichword(__pos)]; }
 
       block_type&
-      _M_hiword()
+      _M_hiword() noexcept
       { return this->_M_w[_M_w.size() - 1]; }
 
       block_type
-      _M_hiword() const
+      _M_hiword() const noexcept
       { return this->_M_w[_M_w.size() - 1]; }
 
       void
-      _M_do_and(const __dynamic_bitset_base& __x)
+      _M_do_and(const __dynamic_bitset_base& __x) noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -175,7 +181,7 @@ namespace tr2
       }
 
       void
-      _M_do_or(const __dynamic_bitset_base& __x)
+      _M_do_or(const __dynamic_bitset_base& __x) noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -185,7 +191,7 @@ namespace tr2
       }
 
       void
-      _M_do_xor(const __dynamic_bitset_base& __x)
+      _M_do_xor(const __dynamic_bitset_base& __x) noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -195,7 +201,7 @@ namespace tr2
       }
 
       void
-      _M_do_dif(const __dynamic_bitset_base& __x)
+      _M_do_dif(const __dynamic_bitset_base& __x) noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -211,28 +217,27 @@ namespace tr2
       _M_do_right_shift(size_t __shift);
 
       void
-      _M_do_flip()
+      _M_do_flip() noexcept
       {
 	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
 	  this->_M_w[__i] = ~this->_M_w[__i];
       }
 
       void
-      _M_do_set()
+      _M_do_set() noexcept
       {
 	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
-	  this->_M_w[__i] = ~static_cast<block_type>(0);
+	  this->_M_w[__i] = static_cast<block_type>(-1);
       }
 
       void
-      _M_do_reset()
+      _M_do_reset() noexcept
       {
-	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
-	  this->_M_w[__i] = static_cast<block_type>(0);
+	std::fill(_M_w.begin(), _M_w.end(), static_cast<block_type>(0));
       }
 
       bool
-      _M_is_equal(const __dynamic_bitset_base& __x) const
+      _M_is_equal(const __dynamic_bitset_base& __x) const noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  {
@@ -246,7 +251,7 @@ namespace tr2
       }
 
       bool
-      _M_is_less(const __dynamic_bitset_base& __x) const
+      _M_is_less(const __dynamic_bitset_base& __x) const noexcept
       {
 	if (__x._M_w.size() == this->_M_w.size())
 	  {
@@ -264,17 +269,17 @@ namespace tr2
       }
 
       size_t
-      _M_are_all_aux() const
+      _M_are_all_aux() const noexcept
       {
 	for (size_t __i = 0; __i < this->_M_w.size() - 1; ++__i)
-	  if (_M_w[__i] != ~static_cast<block_type>(0))
+	  if (_M_w[__i] != static_cast<block_type>(-1))
 	    return 0;
 	return ((this->_M_w.size() - 1) * _S_bits_per_block
 		+ __builtin_popcountll(this->_M_hiword()));
       }
 
       bool
-      _M_is_any() const
+      _M_is_any() const noexcept
       {
 	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
 	  if (this->_M_w[__i] != static_cast<block_type>(0))
@@ -283,7 +288,7 @@ namespace tr2
       }
 
       bool
-      _M_is_subset_of(const __dynamic_bitset_base& __b)
+      _M_is_subset_of(const __dynamic_bitset_base& __b) noexcept
       {
 	if (__b._M_w.size() == this->_M_w.size())
 	  {
@@ -297,7 +302,7 @@ namespace tr2
       }
 
       bool
-      _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const
+      _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const noexcept
       {
 	if (this->is_subset_of(__b))
 	  {
@@ -311,7 +316,7 @@ namespace tr2
       }
 
       size_t
-      _M_do_count() const
+      _M_do_count() const noexcept
       {
 	size_t __result = 0;
 	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
@@ -357,6 +362,7 @@ namespace tr2
    *
    *  See N2050,
    *  Proposal to Add a Dynamically Sizeable Bitset to the Standard Library.
+   *  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2050.pdf
    *
    *  In the general unoptimized case, storage is allocated in
    *  word-sized blocks.  Let B be the number of bits in a word, then
@@ -435,7 +441,7 @@ namespace tr2
       {
 	size_type __shift = this->_M_Nb % bits_per_block;
 	if (__shift > 0)
-	  this->_M_hiword() &= ~((~static_cast<block_type>(0)) << __shift);
+	  this->_M_hiword() &= block_type(~(block_type(-1) << __shift));
       }
 
       //  Set the unused bits in the uppermost word.
@@ -444,22 +450,22 @@ namespace tr2
       {
 	size_type __shift = this->_M_Nb % bits_per_block;
 	if (__shift > 0)
-	  this->_M_hiword() |= ((~static_cast<block_type>(0)) << __shift);
+	  this->_M_hiword() |= block_type(block_type(-1) << __shift);
       }
 
       /**
        *  These versions of single-bit set, reset, flip, and test
        *  do no range checking.
        */
-      dynamic_bitset<_WordT, _Alloc>&
-      _M_unchecked_set(size_type __pos)
+      dynamic_bitset&
+      _M_unchecked_set(size_type __pos) noexcept
       {
 	this->_M_getword(__pos) |= _Base::_S_maskbit(__pos);
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      _M_unchecked_set(size_type __pos, int __val)
+      dynamic_bitset&
+      _M_unchecked_set(size_type __pos, int __val) noexcept
       {
 	if (__val)
 	  this->_M_getword(__pos) |= _Base::_S_maskbit(__pos);
@@ -468,26 +474,26 @@ namespace tr2
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      _M_unchecked_reset(size_type __pos)
+      dynamic_bitset&
+      _M_unchecked_reset(size_type __pos) noexcept
       {
 	this->_M_getword(__pos) &= ~_Base::_S_maskbit(__pos);
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      _M_unchecked_flip(size_type __pos)
+      dynamic_bitset&
+      _M_unchecked_flip(size_type __pos) noexcept
       {
 	this->_M_getword(__pos) ^= _Base::_S_maskbit(__pos);
 	return *this;
       }
 
       bool
-      _M_unchecked_test(size_type __pos) const
+      _M_unchecked_test(size_type __pos) const noexcept
       { return ((this->_M_getword(__pos) & _Base::_S_maskbit(__pos))
 		!= static_cast<_WordT>(0)); }
 
-      size_type _M_Nb;
+      size_type _M_Nb = 0;
 
     public:
       /**
@@ -511,22 +517,16 @@ namespace tr2
 	block_type *_M_wp;
 	size_type _M_bpos;
 
-	// left undefined
-	reference();
-
       public:
-	reference(dynamic_bitset& __b, size_type __pos)
+	reference(dynamic_bitset& __b, size_type __pos) noexcept
 	{
 	  this->_M_wp = &__b._M_getword(__pos);
 	  this->_M_bpos = _Base::_S_whichbit(__pos);
 	}
 
-	~reference()
-	{ }
-
 	// For b[i] = __x;
 	reference&
-	operator=(bool __x)
+	operator=(bool __x) noexcept
 	{
 	  if (__x)
 	    *this->_M_wp |= _Base::_S_maskbit(this->_M_bpos);
@@ -537,7 +537,7 @@ namespace tr2
 
 	// For b[i] = b[__j];
 	reference&
-	operator=(const reference& __j)
+	operator=(const reference& __j) noexcept
 	{
 	  if ((*(__j._M_wp) & _Base::_S_maskbit(__j._M_bpos)))
 	    *this->_M_wp |= _Base::_S_maskbit(this->_M_bpos);
@@ -548,16 +548,16 @@ namespace tr2
 
 	// Flips the bit
 	bool
-	operator~() const
+	operator~() const noexcept
 	{ return (*(_M_wp) & _Base::_S_maskbit(this->_M_bpos)) == 0; }
 
 	// For __x = b[i];
-	operator bool() const
+	operator bool() const noexcept
 	{ return (*(this->_M_wp) & _Base::_S_maskbit(this->_M_bpos)) != 0; }
 
 	// For b[i].flip();
 	reference&
-	flip()
+	flip() noexcept
 	{
 	  *this->_M_wp ^= _Base::_S_maskbit(this->_M_bpos);
 	  return *this;
@@ -569,10 +569,14 @@ namespace tr2
       typedef bool const_reference;
 
       // 23.3.5.1 constructors:
+
+      /// All bits set to zero.
+      dynamic_bitset() = default;
+
       /// All bits set to zero.
       explicit
-      dynamic_bitset(const allocator_type& __alloc = allocator_type())
-      : _Base(__alloc), _M_Nb(0)
+      dynamic_bitset(const allocator_type& __alloc)
+      : _Base(__alloc)
       { }
 
       /// Initial bits bitwise-copied from a single word (others set to zero).
@@ -585,7 +589,7 @@ namespace tr2
 
       dynamic_bitset(initializer_list<block_type> __il,
 		     const allocator_type& __alloc = allocator_type())
-      : _Base(__alloc), _M_Nb(0)
+      : _Base(__alloc)
       { this->append(__il); }
 
       /**
@@ -609,8 +613,7 @@ namespace tr2
 		       __n = std::basic_string<_CharT, _Traits, _Alloc1>::npos,
 		       _CharT __zero = _CharT('0'), _CharT __one = _CharT('1'),
 		       const allocator_type& __alloc = allocator_type())
-	: _Base(__alloc),
-	  _M_Nb(0) // Watch for npos.
+	: _Base(__alloc)
 	{
 	  if (__pos > __str.size())
 	    __throw_out_of_range(__N("dynamic_bitset::bitset initial position "
@@ -619,8 +622,7 @@ namespace tr2
 	  // Watch for npos.
 	  this->_M_Nb = (__n > __str.size() ? __str.size() - __pos : __n);
 	  this->resize(this->_M_Nb);
-	  this->_M_copy_from_string(__str, __pos, __n,
-				    _CharT('0'), _CharT('1'));
+	  this->_M_copy_from_string(__str, __pos, __n);
 	}
 
       /**
@@ -633,61 +635,42 @@ namespace tr2
       explicit
       dynamic_bitset(const char* __str,
 		     const allocator_type& __alloc = allocator_type())
-      : _Base(__alloc)
+      : _Base(__builtin_strlen(__str), 0ULL, __alloc),
+	_M_Nb(__builtin_strlen(__str))
       {
-	size_t __len = 0;
-	if (__str)
-	  while (__str[__len] != '\0')
-	    ++__len;
-	this->resize(__len);
-	this->_M_copy_from_ptr<char,std::char_traits<char>>
-		   (__str, __len, 0, __len, '0', '1');
+	this->_M_copy_from_ptr(__str, _M_Nb, 0, _M_Nb);
       }
 
-      /**
-       *  @brief  Copy constructor.
-       */
-      dynamic_bitset(const dynamic_bitset& __b)
-      : _Base(__b), _M_Nb(__b.size())
-      { }
+      /// Copy constructor.
+      dynamic_bitset(const dynamic_bitset&) = default;
 
-      /**
-       *  @brief  Move constructor.
-       */
-      dynamic_bitset(dynamic_bitset&& __b)
-      : _Base(std::forward<_Base>(__b)), _M_Nb(__b.size())
-      { }
+      /// Move constructor.
+      dynamic_bitset(dynamic_bitset&& __b) noexcept
+      : _Base(std::move(__b)), _M_Nb(__b._M_Nb)
+      { __b.clear(); }
 
-      /**
-       *  @brief  Swap with another bitset.
-       */
+      /// Swap with another bitset.
       void
-      swap(dynamic_bitset& __b)
+      swap(dynamic_bitset& __b) noexcept
       {
 	this->_M_swap(__b);
 	std::swap(this->_M_Nb, __b._M_Nb);
       }
 
-      /**
-       *  @brief  Assignment.
-       */
-      dynamic_bitset&
-      operator=(const dynamic_bitset& __b)
-      {
-	if (&__b != this)
-	  {
-	    this->_M_assign(__b);
-	    this->_M_Nb = __b._M_Nb;
-	  }
-      }
+      /// Copy assignment operator.
+      dynamic_bitset& operator=(const dynamic_bitset&) = default;
 
-      /**
-       *  @brief  Move assignment.
-       */
+      /// Move assignment operator.
       dynamic_bitset&
       operator=(dynamic_bitset&& __b)
+      noexcept(std::is_nothrow_move_assignable<_Base>::value)
       {
-	this->swap(__b);
+	static_cast<_Base&>(*this) = static_cast<_Base&&>(__b);
+	_M_Nb = __b._M_Nb;
+	if _GLIBCXX17_CONSTEXPR (std::is_nothrow_move_assignable<_Base>::value)
+	  __b._M_Nb = 0;
+	else if (get_allocator() == __b.get_allocator())
+	  __b._M_Nb = 0;
 	return *this;
       }
 
@@ -695,7 +678,7 @@ namespace tr2
        *  @brief  Return the allocator for the bitset.
        */
       allocator_type
-      get_allocator() const
+      get_allocator() const noexcept
       { return this->_M_get_allocator(); }
 
       /**
@@ -734,6 +717,8 @@ namespace tr2
 	++this->_M_Nb;
       }
 
+      // XXX why is there no pop_back() member in the proposal?
+
       /**
        *  @brief  Append a block.
        */
@@ -770,36 +755,36 @@ namespace tr2
        *
        *  These should be self-explanatory.
        */
-      dynamic_bitset<_WordT, _Alloc>&
-      operator&=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+      dynamic_bitset&
+      operator&=(const dynamic_bitset& __rhs)
       {
 	this->_M_do_and(__rhs);
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      operator&=(dynamic_bitset<_WordT, _Alloc>&& __rhs)
+      dynamic_bitset&
+      operator&=(dynamic_bitset&& __rhs)
       {
 	this->_M_do_and(std::move(__rhs));
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      operator|=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+      dynamic_bitset&
+      operator|=(const dynamic_bitset& __rhs)
       {
 	this->_M_do_or(__rhs);
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      operator^=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+      dynamic_bitset&
+      operator^=(const dynamic_bitset& __rhs)
       {
 	this->_M_do_xor(__rhs);
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
-      operator-=(const dynamic_bitset<_WordT, _Alloc>& __rhs)
+      dynamic_bitset&
+      operator-=(const dynamic_bitset& __rhs)
       {
 	this->_M_do_dif(__rhs);
 	return *this;
@@ -813,7 +798,7 @@ namespace tr2
        *
        *  These should be self-explanatory.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       operator<<=(size_type __pos)
       {
 	if (__builtin_expect(__pos < this->_M_Nb, 1))
@@ -826,7 +811,7 @@ namespace tr2
 	return *this;
       }
 
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       operator>>=(size_type __pos)
       {
 	if (__builtin_expect(__pos < this->_M_Nb, 1))
@@ -844,7 +829,7 @@ namespace tr2
       /**
        *  @brief Sets every bit to true.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       set()
       {
 	this->_M_do_set();
@@ -858,7 +843,7 @@ namespace tr2
        *  @param  __val  Either true or false, defaults to true.
        *  @throw  std::out_of_range  If @a __pos is bigger the size of the %set.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       set(size_type __pos, bool __val = true)
       {
 	if (__pos >= _M_Nb)
@@ -869,7 +854,7 @@ namespace tr2
       /**
        *  @brief Sets every bit to false.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       reset()
       {
 	this->_M_do_reset();
@@ -883,7 +868,7 @@ namespace tr2
        *
        *  Same as writing @c set(__pos, false).
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       reset(size_type __pos)
       {
 	if (__pos >= _M_Nb)
@@ -894,7 +879,7 @@ namespace tr2
       /**
        *  @brief Toggles every bit to its opposite value.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       flip()
       {
 	this->_M_do_flip();
@@ -907,7 +892,7 @@ namespace tr2
        *  @param  __pos  The index of the bit.
        *  @throw  std::out_of_range  If @a __pos is bigger the size of the %set.
        */
-      dynamic_bitset<_WordT, _Alloc>&
+      dynamic_bitset&
       flip(size_type __pos)
       {
 	if (__pos >= _M_Nb)
@@ -916,7 +901,7 @@ namespace tr2
       }
 
       /// See the no-argument flip().
-      dynamic_bitset<_WordT, _Alloc>
+      dynamic_bitset
       operator~() const
       { return dynamic_bitset<_WordT, _Alloc>(*this).flip(); }
 
@@ -978,19 +963,23 @@ namespace tr2
 	}
 
       // Helper functions for string operations.
-      template<typename _CharT, typename _Traits>
+      template<typename _Traits = std::char_traits<char>,
+	       typename _CharT = typename _Traits::char_type>
 	void
 	_M_copy_from_ptr(const _CharT*, size_t, size_t, size_t,
-			 _CharT, _CharT);
+			 _CharT __zero = _CharT('0'),
+			 _CharT __one = _CharT('1'));
 
       template<typename _CharT, typename _Traits, typename _Alloc1>
 	void
-	_M_copy_from_string(const std::basic_string<_CharT,
-			    _Traits, _Alloc1>& __str, size_t __pos, size_t __n,
+	_M_copy_from_string(const basic_string<_CharT, _Traits, _Alloc1>& __str,
+			    size_t __pos, size_t __n,
 			    _CharT __zero = _CharT('0'),
 			    _CharT __one = _CharT('1'))
-	{ _M_copy_from_ptr<_CharT, _Traits>(__str.data(), __str.size(),
-					    __pos, __n, __zero, __one); }
+	{
+	  _M_copy_from_ptr<_Traits>(__str.data(), __str.size(), __pos, __n,
+				    __zero, __one);
+	}
 
       template<typename _CharT, typename _Traits, typename _Alloc1>
 	void
@@ -1065,13 +1054,13 @@ namespace tr2
 
       //@{
       /// Self-explanatory.
-      dynamic_bitset<_WordT, _Alloc>
+      dynamic_bitset
       operator<<(size_type __pos) const
-      { return dynamic_bitset<_WordT, _Alloc>(*this) <<= __pos; }
+      { return dynamic_bitset(*this) <<= __pos; }
 
-      dynamic_bitset<_WordT, _Alloc>
+      dynamic_bitset
       operator>>(size_type __pos) const
-      { return dynamic_bitset<_WordT, _Alloc>(*this) >>= __pos; }
+      { return dynamic_bitset(*this) >>= __pos; }
       //@}
 
       /**
@@ -1102,14 +1091,14 @@ namespace tr2
       { return this->_M_is_proper_subset_of(__b); }
 
       friend bool
-      operator==(const dynamic_bitset<_WordT, _Alloc>& __lhs,
-		 const dynamic_bitset<_WordT, _Alloc>& __rhs)
-      { return __lhs._M_is_equal(__rhs); }
+      operator==(const dynamic_bitset& __lhs,
+		 const dynamic_bitset& __rhs) noexcept
+      { return __lhs._M_Nb == __rhs._M_Nb && __lhs._M_is_equal(__rhs); }
 
       friend bool
-      operator<(const dynamic_bitset<_WordT, _Alloc>& __lhs,
-		const dynamic_bitset<_WordT, _Alloc>& __rhs)
-      { return __lhs._M_is_less(__rhs); }
+      operator<(const dynamic_bitset& __lhs,
+		const dynamic_bitset& __rhs) noexcept
+      { return __lhs._M_is_less(__rhs) || __lhs._M_Nb < __rhs._M_Nb; }
     };
 
   template<typename _WordT, typename _Alloc>
diff --git a/libstdc++-v3/include/tr2/dynamic_bitset.tcc b/libstdc++-v3/include/tr2/dynamic_bitset.tcc
index 8228d7bc472..bbd2cb3bb04 100644
--- a/libstdc++-v3/include/tr2/dynamic_bitset.tcc
+++ b/libstdc++-v3/include/tr2/dynamic_bitset.tcc
@@ -174,7 +174,7 @@ namespace tr2
 
   // Definitions of non-inline member functions.
   template<typename _WordT, typename _Alloc>
-    template<typename _CharT, typename _Traits>
+    template<typename _Traits, typename _CharT>
       void
       dynamic_bitset<_WordT, _Alloc>::
       _M_copy_from_ptr(const _CharT* __str, size_t __len,
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc
new file mode 100644
index 00000000000..a811307c73a
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  std::tr2::dynamic_bitset<> b = a;
+  VERIFY( a == b );
+  b.resize(99);
+  VERIFY( a != b );
+}
+
+void
+test02()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  std::tr2::dynamic_bitset<> b = a;
+  VERIFY( !(a < b) );
+  VERIFY( !(b < a) );
+  b.resize(99);
+  VERIFY( !(a < b) );
+  VERIFY( b < a );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc
new file mode 100644
index 00000000000..9e21a91ff52
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc
@@ -0,0 +1,105 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::tr2::dynamic_bitset<> a;
+  VERIFY( a.size() == 0 );
+  VERIFY( a.empty() );
+  std::tr2::dynamic_bitset<> b(1);
+  VERIFY( b.size() == 1 );
+  VERIFY( !b.empty() );
+  VERIFY( a != b );
+}
+
+void
+test02()
+{
+  std::tr2::dynamic_bitset<> a(1, 0); // { 0 }
+  std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test03()
+{
+  std::tr2::dynamic_bitset<> a;
+  a.resize(1);                        // { 0 }
+  std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test04()
+{
+  std::tr2::dynamic_bitset<> a(3, 2); // { 0, 1, 0 }
+  std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test05()
+{
+  std::tr2::dynamic_bitset<unsigned short> a(1, 0); // { 0 }
+  std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test06()
+{
+  std::tr2::dynamic_bitset<unsigned short> a;
+  a.resize(1);                                      // { 0 }
+  std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test07()
+{
+  std::tr2::dynamic_bitset<unsigned short> a(3, 2); // { 0, 1, 0 }
+  std::tr2::dynamic_bitset<unsigned short> b(2, 2); // { 0, 1 }
+  VERIFY( a != b );
+}
+
+void
+test08()
+{
+  std::tr2::dynamic_bitset<> a(65, -1ULL);
+  std::tr2::dynamic_bitset<> b(64, -1ULL);
+  b.push_back(0);
+  VERIFY( a == b );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+  test06();
+  test07();
+  test08();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc
new file mode 100644
index 00000000000..06bc1158a82
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  const auto n = a.num_blocks();
+  std::tr2::dynamic_bitset<> b = a;
+  VERIFY(b.num_blocks() == n);
+  VERIFY(b.size() == 100);
+  VERIFY(a.num_blocks() == n);
+  VERIFY(a.size() == 100);
+  VERIFY(b == a);
+}
+
+void
+test02()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  const auto n = a.num_blocks();
+  std::tr2::dynamic_bitset<> b;
+  b = a;
+  VERIFY(b.num_blocks() == n);
+  VERIFY(b.size() == 100);
+  VERIFY(a.num_blocks() == n);
+  VERIFY(a.size() == 100);
+  VERIFY(b == a);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc
new file mode 100644
index 00000000000..ed320db300d
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  const auto n = a.num_blocks();
+  std::tr2::dynamic_bitset<> b = std::move(a);
+  VERIFY(b.num_blocks() == n);
+  VERIFY(b.size() == 100);
+  VERIFY(a.num_blocks() == 0);
+  VERIFY(a.size() == 0);
+}
+
+void
+test02()
+{
+  std::tr2::dynamic_bitset<> a(100);
+  const auto n = a.num_blocks();
+  std::tr2::dynamic_bitset<> b;
+  b = std::move(a);
+  VERIFY(b.num_blocks() == n);
+  VERIFY(b.size() == 100);
+  VERIFY(a.num_blocks() == 0);
+  VERIFY(a.size() == 0);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc
new file mode 100644
index 00000000000..0aec1adf65b
--- /dev/null
+++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <tr2/dynamic_bitset>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  // PR libstdc++/92059
+  std::tr2::dynamic_bitset<> b1(10000), b2(10000);
+  b2 = b1; // crashed on missing return
+  VERIFY( b2 == b1);
+}
+
+int
+main()
+{
+  test01();
+}


More information about the Gcc-patches mailing list