[gcc r12-1817] libstdc++: Implement LWG 581 for std:ostream::flush()

Jonathan Wakely redi@gcc.gnu.org
Fri Jun 25 19:51:09 GMT 2021


https://gcc.gnu.org/g:f8c5b542f6cb6a947600e34420565ac67486ea14

commit r12-1817-gf8c5b542f6cb6a947600e34420565ac67486ea14
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jun 25 18:31:23 2021 +0100

    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:
---
 libstdc++-v3/doc/html/manual/bugs.html             |  3 ++
 libstdc++-v3/doc/xml/manual/intro.xml              |  6 +++
 libstdc++-v3/include/bits/basic_ios.tcc            |  2 +-
 libstdc++-v3/include/bits/ostream.tcc              | 35 ++++++++++------
 .../testsuite/27_io/basic_ostream/flush/char/2.cc  | 48 +++++++++++++++++-----
 .../flush/char/exceptions_badbit_throw.cc          | 16 ++++----
 .../27_io/basic_ostream/flush/wchar_t/2.cc         | 48 +++++++++++++++++-----
 .../flush/wchar_t/exceptions_badbit_throw.cc       | 16 ++++----
 8 files changed, 126 insertions(+), 48 deletions(-)

diff --git a/libstdc++-v3/doc/html/manual/bugs.html b/libstdc++-v3/doc/html/manual/bugs.html
index 7e0837322e5..7b49e4ab87c 100644
--- a/libstdc++-v3/doc/html/manual/bugs.html
+++ b/libstdc++-v3/doc/html/manual/bugs.html
@@ -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).
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
-	{
-	  if (this->rdbuf() && this->rdbuf()->pubsync() == -1)
-	    __err |= ios_base::badbit;
-	}
-      __catch(__cxxabiv1::__forced_unwind&)
+      // 581. flush() not unformatted function
+      // basic_ostream::flush() *is* an unformatted output function.
+      if (__streambuf_type* __buf = this->rdbuf())
 	{
-	  this->_M_setstate(ios_base::badbit);		
-	  __throw_exception_again;
+	  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(...)
-	{ 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 );
     }


More information about the Libstdc++-cvs mailing list