The bug here is that we called putback even if the initial __is >> __ch extraction failed and set eofbit, and putback clears the eofbit. I found a number of other problems though, such as not even trying to call putback after failing to find the ',' and ')' characters.
I decided to rewrite the function following the proposed resolution for https://wg21.link/lwg2714 which is a much more precise specification for much more desirable semantics. 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. Tested powerpc64le-linux, committed to trunk. For the release branches I'm considering just fixing the bug that clears eofbit, and not the whole rewrite of the function.
commit 419381b5d32b5a38c1fe7703dc0400c836106939 Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Wed Dec 13 17:02:14 2017 +0000 PR libstdc++/59568 fix error handling for std::complex stream extraction 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255608 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex index 61f8cc1fce3..bfe10347bd3 100644 --- a/libstdc++-v3/include/std/complex +++ b/libstdc++-v3/include/std/complex @@ -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 index 00000000000..6b35e8adcf9 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/complex/dr2714.cc @@ -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(); +}