This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[libstdc++,3.1] fix libstdc++/6282


The patch was finished at the same time I changed the PR to "patch in
progress," but it's such a corner case that I put this on hold until 3.1
was out.

A length of zero wouldn't be explicitly chosen by a user, but could easily
be generated by other template code.

Rather than continuing to store a word that goes unused, and add checks
to the single-word specialization, I added a second specialization which
stores no state at all.  This means a weird implementation for _M_getword.

tested 1686-pc-linux-gnu, trunk and branch


2002-05-24  Phil Edwards  <pme@gcc.gnu.org>

	PR libstdc++/6282
	* include/std/std_bitset.h (_Base_biteset<0>):  New specialization.
	(operator>>):  If nothing was extracted, don't fail in the
	zero-length case.
	* testsuite/23_containers/bitset_ctor.cc (test02):  New test.


Index: include/std/std_bitset.h
===================================================================
RCS file: /home/pme/Repositories/GCC/gcc/libstdc++-v3/include/std/std_bitset.h,v
retrieving revision 1.6
diff -u -3 -p -r1.6 std_bitset.h
--- include/std/std_bitset.h	1 May 2002 22:57:58 -0000	1.6
+++ include/std/std_bitset.h	2 May 2002 09:01:23 -0000
@@ -61,7 +61,7 @@
 
 #define _GLIBCPP_BITSET_BITS_PER_WORD (CHAR_BIT*sizeof(unsigned long))
 #define _GLIBCPP_BITSET_WORDS(__n) \
- ((__n) < 1 ? 1 : ((__n) + _GLIBCPP_BITSET_BITS_PER_WORD - 1)/_GLIBCPP_BITSET_BITS_PER_WORD)
+ ((__n) < 1 ? 0 : ((__n) + _GLIBCPP_BITSET_BITS_PER_WORD - 1)/_GLIBCPP_BITSET_BITS_PER_WORD)
 
 namespace std
 {
@@ -463,6 +463,101 @@ namespace std
       _M_do_find_next(size_t __prev, size_t __not_found) const;
     };
 
+
+  /**
+   *  @if maint
+   *  Base class, specialization for no storage (zero-length %bitset).
+   *
+   *  See documentation for bitset.
+   *  @endif
+  */
+  template<>
+    struct _Base_bitset<0>
+    {
+      typedef unsigned long _WordT;
+
+      _Base_bitset() {}
+      _Base_bitset(unsigned long) {}
+
+      static size_t
+      _S_whichword(size_t __pos )
+      { return __pos / _GLIBCPP_BITSET_BITS_PER_WORD; }
+
+      static size_t
+      _S_whichbyte(size_t __pos )
+      { return (__pos % _GLIBCPP_BITSET_BITS_PER_WORD) / CHAR_BIT; }
+
+      static size_t
+      _S_whichbit(size_t __pos )
+      {  return __pos % _GLIBCPP_BITSET_BITS_PER_WORD; }
+
+      static _WordT
+      _S_maskbit(size_t __pos )
+      { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); }
+
+      // This would normally give access to the data.  The bounds-checking
+      // in the bitset class will prevent the user from getting this far,
+      // but (1) it must still return an lvalue to compile, and (2) the
+      // user might call _Unchecked_set directly, in which case this /needs/
+      // to fail.  Let's not penalize zero-length users unless they actually
+      // make an unchecked call; all the memory ugliness is therefore
+      // localized to this single should-never-get-this-far function.
+      _WordT&
+      _M_getword(size_t) const
+      { __throw_out_of_range("bitset -- zero-length"); return *new _WordT; }
+
+      _WordT
+      _M_hiword() const { return 0; }
+
+      void
+      _M_do_and(const _Base_bitset<0>&) { }
+
+      void
+      _M_do_or(const _Base_bitset<0>&)  { }
+
+      void
+      _M_do_xor(const _Base_bitset<0>&) { }
+
+      void
+      _M_do_left_shift(size_t) { }
+
+      void
+      _M_do_right_shift(size_t) { }
+
+      void
+      _M_do_flip() { }
+
+      void
+      _M_do_set() { }
+
+      void
+      _M_do_reset() { }
+
+      // Are all empty bitsets equal to each other?  Are they equal to
+      // themselves?  How to compare a thing which has no state?  What is
+      // the sound of one zero-length bitset clapping?
+      bool
+      _M_is_equal(const _Base_bitset<0>&) const { return true; }
+
+      bool
+      _M_is_any() const { return false; }
+
+      size_t
+      _M_do_count() const { return 0; }
+
+      unsigned long
+      _M_do_to_ulong() const { return 0; }
+
+      // Normally "not found" is the size, but that could also be
+      // misinterpreted as an index in this corner case.  Oh well.
+      size_t
+      _M_do_find_first(size_t) const { return 0; }
+
+      size_t
+      _M_do_find_next(size_t, size_t) const { return 0; }
+    };
+
+
   // Helper class to zero out the unused high-order bits in the highest word.
   template<size_t _Extrabits>
     struct _Sanitize
@@ -1115,7 +1210,7 @@ namespace std
 		}
 	    }
 
-	  if (__tmp.empty())
+	  if (__tmp.empty() && !_Nb)
 	    __is.setstate(ios_base::failbit);
 	  else
 	    __x._M_copy_from_string(__tmp, static_cast<size_t>(0), _Nb);
Index: testsuite/23_containers/bitset_ctor.cc
===================================================================
RCS file: /home/pme/Repositories/GCC/gcc/libstdc++-v3/testsuite/23_containers/bitset_ctor.cc,v
retrieving revision 1.5
diff -u -3 -p -r1.5 bitset_ctor.cc
--- testsuite/23_containers/bitset_ctor.cc	13 Feb 2002 18:29:12 -0000	1.5
+++ testsuite/23_containers/bitset_ctor.cc	12 Apr 2002 21:04:11 -0000
@@ -81,9 +81,46 @@ bool test01(void)
   return test;
 }
 
+// boundary condition:  a zero-sized set
+// libstdc++/6282
+bool test02(void)
+{
+  using std::char_traits;  using std::allocator;
+  bool test = true;
+
+  std::bitset<0>  z1;
+  VERIFY( z1.any() == false );
+
+  std::bitset<0>  z2(12345);
+  VERIFY( z2.any() == false );
+
+  std::bitset<0>  z3(std::string("10101010101"));
+  VERIFY( z3.any() == false );
+
+  try {
+    z1.set(0);
+    VERIFY( false );
+  }
+  catch(std::out_of_range& fail) {
+    VERIFY( true );
+  }
+  catch(...) {
+    VERIFY( false );
+  }
+
+  VERIFY( z1.to_ulong() == 0 );
+  VERIFY( ( z1.to_string<char,char_traits<char>,allocator<char> >().empty() ) );
+
+#ifdef DEBUG_ASSERT
+  assert(test);
+#endif
+  return test;
+}
+
 int main()
 {
   test01();
+  test02();
 
   return 0;
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]