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

Reply via email to