diff --git a/libcxx/include/locale b/libcxx/include/locale index a86645d2cc4b..52885b768db2 100644 --- a/libcxx/include/locale +++ b/libcxx/include/locale @@ -768,10 +768,10 @@ __num_get_unsigned_integral(const char* __a, const char* __a_end, { if (__a != __a_end) { - if (*__a == '-') - { - __err = ios_base::failbit; - return 0; + const bool __negate = *__a == '-'; + if (__negate && ++__a == __a_end) { + __err = ios_base::failbit; + return 0; } typename remove_reference::type __save_errno = errno; errno = 0; @@ -785,13 +785,14 @@ __num_get_unsigned_integral(const char* __a, const char* __a_end, __err = ios_base::failbit; return 0; } - else if (__current_errno == ERANGE || - numeric_limits<_Tp>::max() < __ll) + else if (__current_errno == ERANGE || numeric_limits<_Tp>::max() < __ll) { __err = ios_base::failbit; return numeric_limits<_Tp>::max(); } - return static_cast<_Tp>(__ll); + _Tp __res = static_cast<_Tp>(__ll); + if (__negate) __res = -__res; + return __res; } __err = ios_base::failbit; return 0; diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_min_max.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_min_max.pass.cpp index 6ba5a89e61e4..e2218fffb396 100644 --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_min_max.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_min_max.pass.cpp @@ -15,9 +15,17 @@ using namespace std; +template +bool check_stream_failed(std::string const& val) { + istringstream ss(val); + T result; + return !(ss >> result); +} + template void check_limits() { + const bool is_unsigned = std::is_unsigned::value; T minv = numeric_limits::min(); T maxv = numeric_limits::max(); @@ -36,17 +44,12 @@ void check_limits() assert(new_minv == minv); assert(new_maxv == maxv); - if(mins == "0") - mins = "-1"; - else - mins[mins.size() - 1]++; - maxs[maxs.size() - 1]++; - - istringstream maxoss2(maxs), minoss2(mins); - - assert(! (maxoss2 >> new_maxv)); - assert(! (minoss2 >> new_minv)); + assert(check_stream_failed(maxs)); + if (!is_unsigned) { + mins[mins.size() - 1]++; + assert(check_stream_failed(mins)); + } } int main(void) diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_neg_one.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_neg_one.pass.cpp new file mode 100644 index 000000000000..fa0641f618c2 --- /dev/null +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/test_neg_one.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class num_get + +// iter_type get(iter_type in, iter_type end, ios_base&, +// ios_base::iostate& err, unsigned int& v) const; + +#include +#include +#include +#include +#include +#include +#include "test_iterators.h" + +typedef std::num_get > F; + +class my_facet + : public F +{ +public: + explicit my_facet(std::size_t refs = 0) + : F(refs) {} +}; + +template +std::string make_neg_string(T value) { + std::ostringstream ss; + assert(ss << value); + std::string res = ss.str(); + return '-' + res; +} + +template +void test_neg_one() { + const my_facet f(1); + std::ios ios(0); + T v = static_cast(42); + { + const char str[] = "-1"; + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.goodbit); + assert(v == T(-1)); + } + v = 42; + { + const char str[] = "-"; + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == 0); + } +} + +template +void test_negate() { + typedef typename std::make_signed::type SignedT; + const my_facet f(1); + std::ios ios(0); + T v = 42; + { + T value = std::numeric_limits::max(); + ++value; + std::string std_str = make_neg_string(value); + const char* str = std_str.data(); + size_t size = std_str.size(); + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+size+1), + ios, err, v); + assert(iter.base() == str+size); + assert(err == ios.goodbit); + T expected = -value; + assert(v == expected); + } + v = 42; + { + T value = std::numeric_limits::max(); + ++value; + ++value; + std::string std_str = make_neg_string(value); + const char* str = std_str.data(); + size_t size = std_str.size(); + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+size+1), + ios, err, v); + assert(iter.base() == str+size); + assert(err == ios.goodbit); + T expected = -value; + assert(v == expected); + } + v = 42; + { + T value = std::numeric_limits::max(); + std::string std_str = make_neg_string(value); + const char* str = std_str.data(); + size_t size = std_str.size(); + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+size+1), + ios, err, v); + assert(iter.base() == str+size); + assert(err == ios.goodbit); + T expected = -value; + assert(v == expected); + } + v = 42; + { + std::string std_str = make_neg_string(std::numeric_limits::max()); + std_str.back()++; + const char* str = std_str.data(); + size_t size = std_str.size(); + std::ios_base::iostate err = ios.goodbit; + input_iterator iter = + f.get(input_iterator(str), + input_iterator(str+size+1), + ios, err, v); + assert(iter.base() == str+size); + assert(err == ios.failbit); + assert(v == T(-1)); + } +} + +int main(void) +{ + test_neg_one(); + test_neg_one(); + test_neg_one(); + test_neg_one(); + test_neg_one(); + test_neg_one(); + + test_negate(); + test_negate(); + test_negate(); + test_negate(); +}