]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement LWG 415 for std::ws
authorJonathan Wakely <jwakely@redhat.com>
Fri, 25 Jun 2021 20:33:02 +0000 (21:33 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Mon, 28 Jun 2021 12:34:49 +0000 (13:34 +0100)
For C++11 std::ws changed to be an unformatted input function, meaning
it constructs a sentry and sets badbit on exceptions.

libstdc++-v3/ChangeLog:

* doc/xml/manual/intro.xml: Document LWG 415 change.
* doc/html/manual/bugs.html: Regenerate.
* include/bits/istream.tcc (ws): Create sentry and catch
exceptions.
* testsuite/27_io/basic_istream/ws/char/lwg415.cc: New test.
* testsuite/27_io/basic_istream/ws/wchar_t/lwg415.cc: New test.

libstdc++-v3/doc/html/manual/bugs.html
libstdc++-v3/doc/xml/manual/intro.xml
libstdc++-v3/include/bits/istream.tcc
libstdc++-v3/testsuite/27_io/basic_istream/ws/char/lwg415.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/basic_istream/ws/wchar_t/lwg415.cc [new file with mode: 0644]

index 7b49e4ab87cf491e2df2ec6bbe23a4c0e9c0f555..38594a9b75ab68e310e40445caa8d3dc63a45394 100644 (file)
     </p></dd><dt><a id="manual.bugs.dr409"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#409" target="_top">409</a>:
        <span class="emphasis"><em>Closing an fstream should clear the error state</em></span>
     </span></dt><dd><p>Have <code class="code">open</code> clear the error flags.
+    </p></dd><dt><a id="manual.bugs.dr415"></a><span class="term"><a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#415" target="_top">415</a>:
+       <span class="emphasis"><em>Behavior of std::ws</em></span>
+    </span></dt><dd><p>Change it to be an unformatted input function
+      (i.e. construct a sentry and catch exceptions).
     </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-closed.html#431" target="_top">431</a>:
        <span class="emphasis"><em>Swapping containers with unequal allocators</em></span>
     </span></dt><dd><p>Implement Option 3, as per N1599.
index 45762caa711da3ecf46f89aae320585814f56c60..86ed6964b6a84167777bdf16165a341a25d300b4 100644 (file)
@@ -634,6 +634,13 @@ requirements of the license of GCC.
     <listitem><para>Have <code>open</code> clear the error flags.
     </para></listitem></varlistentry>
 
+    <varlistentry xml:id="manual.bugs.dr415"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#415">415</link>:
+       <emphasis>Behavior of std::ws</emphasis>
+    </term>
+    <listitem><para>Change it to be an unformatted input function
+      (i.e. construct a sentry and catch exceptions).
+    </para></listitem></varlistentry>
+
     <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-closed.html#431">431</link>:
        <emphasis>Swapping containers with unequal allocators</emphasis>
     </term>
index 1b046bec93773d0ceee1f051c99d4e7a6c4bb5c8..2a153c2e140a5267b3e67d00cdea3450a2c9d7bb 100644 (file)
@@ -1057,17 +1057,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef typename __istream_type::int_type                __int_type;
       typedef ctype<_CharT>                            __ctype_type;
 
-      const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc());
-      const __int_type __eof = _Traits::eof();
-      __streambuf_type* __sb = __in.rdbuf();
-      __int_type __c = __sb->sgetc();
-
-      while (!_Traits::eq_int_type(__c, __eof)
-            && __ct.is(ctype_base::space, _Traits::to_char_type(__c)))
-       __c = __sb->snextc();
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 451. behavior of std::ws
+      typename __istream_type::sentry __cerb(__in, true);
+      if (__cerb)
+       {
+         ios_base::iostate __err = ios_base::goodbit;
+         __try
+           {
+             const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc());
+             const __int_type __eof = _Traits::eof();
+             __streambuf_type* __sb = __in.rdbuf();
+             __int_type __c = __sb->sgetc();
 
-       if (_Traits::eq_int_type(__c, __eof))
-        __in.setstate(ios_base::eofbit);
+             while (true)
+               {
+                 if (_Traits::eq_int_type(__c, __eof))
+                   {
+                     __err = ios_base::eofbit;
+                     break;
+                   }
+                 if (!__ct.is(ctype_base::space, _Traits::to_char_type(__c)))
+                   break;
+                 __c = __sb->snextc();
+               }
+           }
+         __catch (const __cxxabiv1::__forced_unwind&)
+           {
+             __in._M_setstate(ios_base::badbit);
+             __throw_exception_again;
+           }
+         __catch (...)
+           {
+             __in._M_setstate(ios_base::badbit);
+           }
+         if (__err)
+           __in.setstate(__err);
+       }
       return __in;
     }
 
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/ws/char/lwg415.cc b/libstdc++-v3/testsuite/27_io/basic_istream/ws/char/lwg415.cc
new file mode 100644 (file)
index 0000000..fe6980d
--- /dev/null
@@ -0,0 +1,77 @@
+#include <istream>
+
+// C++11 27.7.2.4 Standard basic_istream manipulators [istream.manip]
+//
+// LWG 415. behavior of std::ws
+// std::ws is an unformatted input function.
+
+#include <istream>
+#include <testsuite_hooks.h>
+#include <testsuite_io.h>
+
+void
+test01()
+{
+  std::istream is(0);
+  VERIFY( is.rdstate() == std::ios_base::badbit );
+
+  is >> std::ws; // sentry should set failbit
+  VERIFY( is.rdstate() & std::ios_base::failbit );
+}
+
+void
+test02()
+{
+  __gnu_test::sync_streambuf buf;
+  std::istream is(&buf);
+
+  __gnu_test::sync_streambuf buf_tie;
+  std::ostream os_tie(&buf_tie);
+
+  // A sentry should be constructed so is.tie()->flush() should be called.
+  // The standard allows the flush to be deferred because the put area of
+  // is_tie is empty, but libstdc++ doesn't defer it.
+  is.tie(&os_tie);
+
+  is >> std::ws;
+
+  VERIFY( is.eof() );
+  VERIFY( !is.fail() );
+  VERIFY( ! buf.sync_called() );
+  VERIFY( buf_tie.sync_called() );
+}
+
+void
+test03()
+{
+  __gnu_test::fail_streambuf buf;
+  std::istream is(&buf);
+
+  char c;
+  is >> c >> std::ws;
+  VERIFY( is.rdstate() == std::ios_base::badbit );
+
+  is.clear();
+  is.exceptions(std::ios_base::badbit);
+
+  try
+  {
+    is >> std::ws;
+    VERIFY( false );
+  }
+  catch (const __gnu_test::underflow_error&)
+  {
+    VERIFY( is.rdstate() == std::ios_base::badbit );
+  }
+  catch (...)
+  {
+    VERIFY( false );
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/ws/wchar_t/lwg415.cc b/libstdc++-v3/testsuite/27_io/basic_istream/ws/wchar_t/lwg415.cc
new file mode 100644 (file)
index 0000000..fd04009
--- /dev/null
@@ -0,0 +1,77 @@
+#include <istream>
+
+// C++11 27.7.2.4 Standard basic_istream manipulators [istream.manip]
+//
+// LWG 415. behavior of std::ws
+// std::ws is an unformatted input function.
+
+#include <istream>
+#include <testsuite_hooks.h>
+#include <testsuite_io.h>
+
+void
+test01()
+{
+  std::wistream is(0);
+  VERIFY( is.rdstate() == std::ios_base::badbit );
+
+  is >> std::ws; // sentry should set failbit
+  VERIFY( is.rdstate() & std::ios_base::failbit );
+}
+
+void
+test02()
+{
+  __gnu_test::sync_wstreambuf buf;
+  std::wistream is(&buf);
+
+  __gnu_test::sync_wstreambuf buf_tie;
+  std::wostream os_tie(&buf_tie);
+
+  // A sentry should be constructed so is.tie()->flush() should be called.
+  // The standard allows the flush to be deferred because the put area of
+  // is_tie is empty, but libstdc++ doesn't defer it.
+  is.tie(&os_tie);
+
+  is >> std::ws;
+
+  VERIFY( is.eof() );
+  VERIFY( !is.fail() );
+  VERIFY( ! buf.sync_called() );
+  VERIFY( buf_tie.sync_called() );
+}
+
+void
+test03()
+{
+  __gnu_test::fail_wstreambuf buf;
+  std::wistream is(&buf);
+
+  wchar_t c;
+  is >> c >> std::ws;
+  VERIFY( is.rdstate() == std::ios_base::badbit );
+
+  is.clear();
+  is.exceptions(std::ios_base::badbit);
+
+  try
+  {
+    is >> std::ws;
+    VERIFY( false );
+  }
+  catch (const __gnu_test::underflow_error&)
+  {
+    VERIFY( is.rdstate() == std::ios_base::badbit );
+  }
+  catch (...)
+  {
+    VERIFY( false );
+  }
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+}