LWG 581 changed ostream::flush() to an unformatted output function for C++11, but it was never implemented in libstdc++.
libstdc++-v3/ChangeLog: * doc/xml/manual/intro.xml: Document LWG 581 change. * doc/html/manual/bugs.html: Regenerate. * include/bits/basic_ios.tcc: Whitespace. * include/bits/ostream.tcc (basic_ostream::flush()): Construct sentry. * testsuite/27_io/basic_ostream/flush/char/2.cc: Check additional cases. * testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc: Likewise. * testsuite/27_io/basic_ostream/flush/wchar_t/2.cc: Likewise. * testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc: Likewise. Tested powerpc64le-linux. Committed to trunk.
commit f8c5b542f6cb6a947600e34420565ac67486ea14 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Jun 25 18:31:23 2021 libstdc++: Implement LWG 581 for std:ostream::flush() LWG 581 changed ostream::flush() to an unformatted output function for C++11, but it was never implemented in libstdc++. libstdc++-v3/ChangeLog: * doc/xml/manual/intro.xml: Document LWG 581 change. * doc/html/manual/bugs.html: Regenerate. * include/bits/basic_ios.tcc: Whitespace. * include/bits/ostream.tcc (basic_ostream::flush()): Construct sentry. * testsuite/27_io/basic_ostream/flush/char/2.cc: Check additional cases. * testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc: Likewise. * testsuite/27_io/basic_ostream/flush/wchar_t/2.cc: Likewise. * testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc: Likewise. diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index 3e7843f58c1..45762caa711 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -743,6 +743,12 @@ requirements of the license of GCC. <listitem><para>In C++11 mode, remove the pow(float,int), etc., signatures. </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr581"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#581">581</link>: + <emphasis><code>flush()</code> not unformatted function</emphasis> + </term> + <listitem><para>Change it to be a unformatted output function (i.e. construct a sentry and catch exceptions). + </para></listitem></varlistentry> + <varlistentry xml:id="manual.bugs.dr586"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#586">586</link>: <emphasis>string inserter not a formatted function</emphasis> </term> diff --git a/libstdc++-v3/include/bits/basic_ios.tcc b/libstdc++-v3/include/bits/basic_ios.tcc index 6285f734031..664a9f22759 100644 --- a/libstdc++-v3/include/bits/basic_ios.tcc +++ b/libstdc++-v3/include/bits/basic_ios.tcc @@ -43,7 +43,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (this->rdbuf()) _M_streambuf_state = __state; else - _M_streambuf_state = __state | badbit; + _M_streambuf_state = __state | badbit; if (this->exceptions() & this->rdstate()) __throw_ios_failure(__N("basic_ios::clear")); } diff --git a/libstdc++-v3/include/bits/ostream.tcc b/libstdc++-v3/include/bits/ostream.tcc index 20585f447ac..d3220e8034b 100644 --- a/libstdc++-v3/include/bits/ostream.tcc +++ b/libstdc++-v3/include/bits/ostream.tcc @@ -213,21 +213,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 60. What is a formatted input function? // basic_ostream::flush() is *not* an unformatted output function. - ios_base::iostate __err = ios_base::goodbit; - __try + // 581. flush() not unformatted function + // basic_ostream::flush() *is* an unformatted output function. + if (__streambuf_type* __buf = this->rdbuf()) { - if (this->rdbuf() && this->rdbuf()->pubsync() == -1) - __err |= ios_base::badbit; + sentry __cerb(*this); + if (__cerb) + { + ios_base::iostate __err = ios_base::goodbit; + __try + { + if (this->rdbuf()->pubsync() == -1) + __err |= ios_base::badbit; + } + __catch(__cxxabiv1::__forced_unwind&) + { + this->_M_setstate(ios_base::badbit); + __throw_exception_again; + } + __catch(...) + { this->_M_setstate(ios_base::badbit); } + if (__err) + this->setstate(__err); + } } - __catch(__cxxabiv1::__forced_unwind&) - { - this->_M_setstate(ios_base::badbit); - __throw_exception_again; - } - __catch(...) - { this->_M_setstate(ios_base::badbit); } - if (__err) - this->setstate(__err); return *this; } diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/2.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/2.cc index 0b33e60bd08..96969debca7 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/2.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/2.cc @@ -22,42 +22,70 @@ // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 60. What is a formatted input function? // basic_ostream::flush() does not behave as an unformatted output function. +// But wait ... +// 581. flush() not unformatted function +// So now basic_ostream::flush() *is* an unformatted output function. #include <ostream> #include <testsuite_hooks.h> #include <testsuite_io.h> +void +test01() +{ + std::ostream os(0); + VERIFY( os.bad() ); + + // Nothing should happen if os.rdbuf() is null. No sentry is constructed. + os.flush(); + VERIFY( os.rdstate() == std::ios_base::badbit ); // no failbit + + os.exceptions(std::ios_base::failbit); + os.flush(); +} + void test02() { __gnu_test::sync_streambuf buf; std::ostream os(&buf); - + __gnu_test::sync_streambuf buf_tie; std::ostream os_tie(&buf_tie); - // No sentry should be constructed so os.tie()->flush() should not be - // called. + // A sentry should be constructed so os.tie()->flush() should be called. os.tie(&os_tie); - + os.flush(); VERIFY( os.good() ); VERIFY( buf.sync_called() ); - VERIFY( !buf_tie.sync_called() ); + VERIFY( buf_tie.sync_called() ); +} - // os.rdbuf()->pubsync() should be called even if !os.good(). +void +test03() +{ + __gnu_test::sync_streambuf buf; + std::ostream os(&buf); + + __gnu_test::sync_streambuf buf_tie; + std::ostream os_tie(&buf_tie); + + os.tie(&os_tie); + + // os.rdbuf()->pubsync() should not be called if !os.good(). os.setstate(std::ios_base::eofbit); os.flush(); - VERIFY( os.rdstate() == std::ios_base::eofbit ); - VERIFY( buf.sync_called() ); + VERIFY( os.rdstate() & std::ios_base::eofbit ); + VERIFY( !buf.sync_called() ); VERIFY( !buf_tie.sync_called() ); } int main() { + test01(); test02(); - return 0; + test03(); } - diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc index bba5fb0baa2..115b00478a7 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/char/exceptions_badbit_throw.cc @@ -28,21 +28,23 @@ void test01() { __gnu_test::fail_streambuf bib; ostream stream(&bib); + + stream.flush(); // should catch exception and set badbit + VERIFY( stream.rdstate() == ios_base::badbit ); + + stream.clear(); stream.exceptions(ios_base::badbit); try { - stream.flush(); + stream.flush(); // should catch exception and set badbit and rethrow VERIFY( false ); } - catch (const __gnu_test::positioning_error&) + catch (const __gnu_test::positioning_error&) { - // stream should set badbit and rethrow facet_error. - VERIFY( stream.bad() ); - VERIFY( (stream.rdstate() & ios_base::failbit) == 0 ); - VERIFY( !stream.eof() ); + VERIFY( stream.rdstate() == ios_base::badbit ); } - catch (...) + catch (...) { VERIFY( false ); } diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/2.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/2.cc index 3711fdedcd5..4403fd3cdf5 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/2.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/2.cc @@ -20,42 +20,70 @@ // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 60. What is a formatted input function? // basic_ostream::flush() does not behave as an unformatted output function. +// But wait ... +// 581. flush() not unformatted function +// So now basic_ostream::flush() *is* an unformatted output function. #include <ostream> #include <testsuite_hooks.h> #include <testsuite_io.h> +void +test01() +{ + std::wostream os(0); + VERIFY( os.bad() ); + + // Nothing should happen if os.rdbuf() is null. No sentry is constructed. + os.flush(); + VERIFY( os.rdstate() == std::ios_base::badbit ); // no failbit + + os.exceptions(std::ios_base::failbit); + os.flush(); +} + void test02() { __gnu_test::sync_wstreambuf buf; std::wostream os(&buf); - + __gnu_test::sync_wstreambuf buf_tie; std::wostream os_tie(&buf_tie); - // No sentry should be constructed so os.tie()->flush() should not be - // called. + // A sentry should be constructed so os.tie()->flush() should be called. os.tie(&os_tie); - + os.flush(); VERIFY( os.good() ); VERIFY( buf.sync_called() ); - VERIFY( !buf_tie.sync_called() ); + VERIFY( buf_tie.sync_called() ); +} - // os.rdbuf()->pubsync() should be called even if !os.good(). +void +test03() +{ + __gnu_test::sync_wstreambuf buf; + std::wostream os(&buf); + + __gnu_test::sync_wstreambuf buf_tie; + std::wostream os_tie(&buf_tie); + + os.tie(&os_tie); + + // os.rdbuf()->pubsync() should not be called if !os.good(). os.setstate(std::ios_base::eofbit); os.flush(); - VERIFY( os.rdstate() == std::ios_base::eofbit ); - VERIFY( buf.sync_called() ); + VERIFY( os.rdstate() & std::ios_base::eofbit ); + VERIFY( !buf.sync_called() ); VERIFY( !buf_tie.sync_called() ); } int main() { + test01(); test02(); - return 0; + test03(); } - diff --git a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc index 86440e14f6f..d88f385a6c3 100644 --- a/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc +++ b/libstdc++-v3/testsuite/27_io/basic_ostream/flush/wchar_t/exceptions_badbit_throw.cc @@ -28,21 +28,23 @@ void test01() { __gnu_test::fail_wstreambuf bib; wostream stream(&bib); + + stream.flush(); // should catch exception and set badbit + VERIFY( stream.rdstate() == ios_base::badbit ); + + stream.clear(); stream.exceptions(ios_base::badbit); try { - stream.flush(); + stream.flush(); // should catch exception and set badbit and rethrow VERIFY( false ); } - catch (const __gnu_test::positioning_error&) + catch (const __gnu_test::positioning_error&) { - // stream should set badbit and rethrow facet_error. - VERIFY( stream.bad() ); - VERIFY( (stream.rdstate() & ios_base::failbit) == 0 ); - VERIFY( !stream.eof() ); + VERIFY( stream.rdstate() == ios_base::badbit ); } - catch (...) + catch (...) { VERIFY( false ); }