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.
This commit is contained in:
Jonathan Wakely 2021-06-25 18:31:23 +01:00
parent 9b6c65c754
commit f8c5b542f6
8 changed files with 126 additions and 48 deletions

View File

@ -303,6 +303,9 @@
</p></dd><dt><a id="manual.bugs.dr550"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#550" target="_top">550</a>:
<span class="emphasis"><em>What should the return type of pow(float,int) be?</em></span>
</span></dt><dd><p>In C++11 mode, remove the pow(float,int), etc., signatures.
</p></dd><dt><a id="manual.bugs.dr581"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#581" target="_top">581</a>:
<span class="emphasis"><em><code class="code">flush()</code> not unformatted function</em></span>
</span></dt><dd><p>Change it to be a unformatted output function (i.e. construct a sentry and catch exceptions).
</p></dd><dt><a id="manual.bugs.dr586"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#586" target="_top">586</a>:
<span class="emphasis"><em>string inserter not a formatted function</em></span>
</span></dt><dd><p>Change it to be a formatted output function (i.e. catch exceptions).

View File

@ -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>

View File

@ -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"));
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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 );
}

View File

@ -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();
}

View File

@ -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 );
}