This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[libstdc++,3.1] fix libstdc++/6282
- From: Phil Edwards <phil at jaj dot com>
- To: libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Fri, 24 May 2002 14:17:06 -0400
- Subject: [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;
}