PR libstdc++/59568 fix error handling for std::complex stream extraction
authorJonathan Wakely <jwakely@redhat.com>
Wed, 13 Dec 2017 17:02:14 +0000 (17:02 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 13 Dec 2017 17:02:14 +0000 (17:02 +0000)
PR libstdc++/59568
* include/std/complex (operator>>): Implement proposed resolution to
LWG 2714. Use putback if and only if a character has been successfully
extracted but isn't a delimiter. Use ctype::widen and traits::eq when
testing if extracted characters match delimiters.
* testsuite/26_numerics/complex/dr2714.cc: New test.

From-SVN: r255608

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/complex
libstdc++-v3/testsuite/26_numerics/complex/dr2714.cc [new file with mode: 0644]

index c8c93350a608379203e9b859ddbed0a400eb0a77..e4e435dccee18c592f40ff3f44a3fbfddef080dc 100644 (file)
@@ -1,3 +1,12 @@
+2017-12-13  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/59568
+       * include/std/complex (operator>>): Implement proposed resolution to
+       LWG 2714. Use putback if and only if a character has been successfully
+       extracted but isn't a delimiter. Use ctype::widen and traits::eq when
+       testing if extracted characters match delimiters.
+       * testsuite/26_numerics/complex/dr2714.cc: New test.
+
 2017-12-12  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/83395
index 61f8cc1fce36a6a0cc412d9363d7077959816309..bfe10347bd3788b12e701fc68b3a6216a0cc7925 100644 (file)
@@ -492,31 +492,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     basic_istream<_CharT, _Traits>&
     operator>>(basic_istream<_CharT, _Traits>& __is, complex<_Tp>& __x)
     {
-      _Tp __re_x, __im_x;
+      bool __fail = true;
       _CharT __ch;
-      __is >> __ch;
-      if (__ch == '(')
+      if (__is >> __ch)
        {
-         __is >> __re_x >> __ch;
-         if (__ch == ',')
+         if (_Traits::eq(__ch, __is.widen('(')))
            {
-             __is >> __im_x >> __ch;
-             if (__ch == ')')
-               __x = complex<_Tp>(__re_x, __im_x);
-             else
-               __is.setstate(ios_base::failbit);
+             _Tp __u;
+             if (__is >> __u >> __ch)
+               {
+                 const _CharT __rparen = __is.widen(')');
+                 if (_Traits::eq(__ch, __rparen))
+                   {
+                     __x = __u;
+                     __fail = false;
+                   }
+                 else if (_Traits::eq(__ch, __is.widen(',')))
+                   {
+                     _Tp __v;
+                     if (__is >> __v >> __ch)
+                       {
+                         if (_Traits::eq(__ch, __rparen))
+                           {
+                             __x = complex<_Tp>(__u, __v);
+                             __fail = false;
+                           }
+                         else
+                           __is.putback(__ch);
+                       }
+                   }
+                 else
+                   __is.putback(__ch);
+               }
            }
-         else if (__ch == ')')
-           __x = __re_x;
          else
-           __is.setstate(ios_base::failbit);
-       }
-      else
-       {
-         __is.putback(__ch);
-         __is >> __re_x;
-         __x = __re_x;
+           {
+             __is.putback(__ch);
+             _Tp __u;
+             if (__is >> __u)
+               {
+                 __x = __u;
+                 __fail = false;
+               }
+           }
        }
+      if (__fail)
+       __is.setstate(ios_base::failbit);
       return __is;
     }
 
diff --git a/libstdc++-v3/testsuite/26_numerics/complex/dr2714.cc b/libstdc++-v3/testsuite/26_numerics/complex/dr2714.cc
new file mode 100644 (file)
index 0000000..6b35e8a
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++98" }
+
+#include <complex>
+#include <sstream>
+#include <complex>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::istringstream in(" 1 (2) ( 2.0 , 0.5 ) ");
+  std::complex<double> c1, c2, c3;
+  in >> c1 >> c2 >> c3;
+  VERIFY( in.good() );
+  VERIFY( c1.real() == 1 && c1.imag() == 0 );
+  VERIFY( c2.real() == 2 && c2.imag() == 0 );
+  VERIFY( c3.real() == 2 && c3.imag() == 0.5 );
+}
+
+void
+test02()
+{
+  std::wistringstream in(L" ( 2.0 , 0.5 ) ");
+  std::complex<double> c;
+  in >> c;
+  VERIFY( in.good() );
+  VERIFY( c.real() == 2.0 && c.imag() == 0.5 );
+}
+
+void
+test03()
+{
+  std::istringstream in;
+  std::complex<double> c(-1, -1);
+  const std::complex<double> c0 = c;
+
+  in.str("a");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+
+  in.str(" ( ) ");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == ')' );
+
+  in.str("(,");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == ',' );
+
+  in.str("(b)");
+  in >> c;
+  VERIFY( in.fail() );
+
+  in.clear();
+  VERIFY( in.get() == 'b' );
+  in.str("( c)");
+
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'c' );
+
+  in.str("(99d");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'd' );
+
+  in.str("(99 e");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'e' );
+
+  in.str("(99, f");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'f' );
+
+  in.str("(99, 88g");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'g' );
+
+  in.str("(99, 88 h");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == 'h' );
+
+  in.str("(99, )");
+  in >> c;
+  VERIFY( in.fail() );
+  in.clear();
+  VERIFY( in.get() == ')' );
+
+  VERIFY( c == c0 );
+}
+
+void
+test04()
+{
+  // PR libstdc++/59568
+  std::istringstream in;
+  std::complex<double> c;
+
+  in.str("");
+  in >> c;
+  VERIFY( in.fail() );
+  VERIFY( in.eof() );
+  in.clear();
+
+  in.str(" ");
+  in >> c;
+  VERIFY( in.fail() );
+  VERIFY( in.eof() );
+  in.clear();
+
+  in.str("(99");
+  in >> c;
+  VERIFY( in.fail() );
+  VERIFY( in.eof() );
+  in.clear();
+
+  in.str("(99,");
+  in >> c;
+  VERIFY( in.fail() );
+  VERIFY( in.eof() );
+  in.clear();
+
+  in.str("(99,99");
+  in >> c;
+  VERIFY( in.fail() );
+  VERIFY( in.eof() );
+  in.clear();
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}