diff --git a/libcxx/include/locale b/libcxx/include/locale index b1cac28fb840..f999cd9846f5 100644 --- a/libcxx/include/locale +++ b/libcxx/include/locale @@ -180,6 +180,7 @@ template <class charT> class messages_byname; #include <__config> #include <__locale> +#include <__debug> #include <algorithm> #include <memory> #include <ios> @@ -755,6 +756,28 @@ __num_get_unsigned_integral(const char* __a, const char* __a_end, return 0; } +template <class _Tp> +_LIBCPP_INLINE_VISIBILITY +_Tp __do_strtod(const char* __a, char** __p2); + +template <> +inline _LIBCPP_INLINE_VISIBILITY +float __do_strtod<float>(const char* __a, char** __p2) { + return strtof_l(__a, __p2, _LIBCPP_GET_C_LOCALE); +} + +template <> +inline _LIBCPP_INLINE_VISIBILITY +double __do_strtod<double>(const char* __a, char** __p2) { + return strtod_l(__a, __p2, _LIBCPP_GET_C_LOCALE); +} + +template <> +inline _LIBCPP_INLINE_VISIBILITY +long double __do_strtod<long double>(const char* __a, char** __p2) { + return strtold_l(__a, __p2, _LIBCPP_GET_C_LOCALE); +} + template <class _Tp> _Tp __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err) @@ -764,7 +787,7 @@ __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err) typename remove_reference<decltype(errno)>::type __save_errno = errno; errno = 0; char *__p2; - long double __ld = strtold_l(__a, &__p2, _LIBCPP_GET_C_LOCALE); + _Tp __ld = __do_strtod<_Tp>(__a, &__p2); typename remove_reference<decltype(errno)>::type __current_errno = errno; if (__current_errno == 0) errno = __save_errno; @@ -775,7 +798,7 @@ __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err) } else if (__current_errno == ERANGE) __err = ios_base::failbit; - return static_cast<_Tp>(__ld); + return __ld; } __err = ios_base::failbit; return 0; @@ -3901,7 +3924,9 @@ wbuffer_convert<_Codecvt, _Elem, _Tr>::underflow() } else { - memmove(__extbuf_, __extbufnext_, __extbufend_ - __extbufnext_); + _LIBCPP_ASSERT(!(__extbufnext_ == NULL && (__extbufend_ != __extbufnext_)), "underflow moving from NULL" ); + if (__extbufend_ != __extbufnext_) + memmove(__extbuf_, __extbufnext_, __extbufend_ - __extbufnext_); __extbufnext_ = __extbuf_ + (__extbufend_ - __extbufnext_); __extbufend_ = __extbuf_ + (__extbuf_ == __extbuf_min_ ? sizeof(__extbuf_min_) : __ebs_); streamsize __nmemb = _VSTD::min(static_cast<streamsize>(this->egptr() - this->eback() - __unget_sz), diff --git a/libcxx/include/support/solaris/xlocale.h b/libcxx/include/support/solaris/xlocale.h index 62b0d74a6d23..e20ef7a6e53b 100644 --- a/libcxx/include/support/solaris/xlocale.h +++ b/libcxx/include/support/solaris/xlocale.h @@ -44,11 +44,6 @@ long strtol_l(const char *__nptr, char **__endptr, return strtol(__nptr, __endptr, __base); } static inline -long double strtold_l(const char *__nptr, char **__endptr, - locale_t __loc) { - return strtold(__nptr, __endptr); -} -static inline unsigned long long strtoull_l(const char *__nptr, char **__endptr, int __base, locale_t __loc) { return strtoull(__nptr, __endptr, __base); @@ -58,6 +53,21 @@ unsigned long strtoul_l(const char *__nptr, char **__endptr, int __base, locale_t __loc) { return strtoul(__nptr, __endptr, __base); } +static inline +float strtof_l(const char *__nptr, char **__endptr, + locale_t __loc) { + return strtof(__nptr, __endptr); +} +static inline +double strtod_l(const char *__nptr, char **__endptr, + locale_t __loc) { + return strtod(__nptr, __endptr); +} +static inline +long double strtold_l(const char *__nptr, char **__endptr, + locale_t __loc) { + return strtold(__nptr, __endptr); +} #ifdef __cplusplus diff --git a/libcxx/include/support/xlocale/__strtonum_fallback.h b/libcxx/include/support/xlocale/__strtonum_fallback.h index b060f7568e00..4ae3918b3d30 100644 --- a/libcxx/include/support/xlocale/__strtonum_fallback.h +++ b/libcxx/include/support/xlocale/__strtonum_fallback.h @@ -19,6 +19,17 @@ #ifdef __cplusplus extern "C" { #endif + +inline _LIBCPP_ALWAYS_INLINE float strtof_l(const char *nptr, + char **endptr, locale_t) { + return ::strtof(nptr, endptr); +} + +inline _LIBCPP_ALWAYS_INLINE double strtod_l(const char *nptr, + char **endptr, locale_t) { + return ::strtod(nptr, endptr); +} + inline _LIBCPP_ALWAYS_INLINE long double strtold_l(const char *nptr, char **endptr, locale_t) { return ::strtold(nptr, endptr); diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp index f5c7c1277c31..6d7f506bb2d4 100644 --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp @@ -207,6 +207,30 @@ int main() assert(err == ios.goodbit); assert(v == 2); } + { + v = -1; + const char str[] = "1.79779e+309"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == HUGE_VAL); + } + { + v = -1; + const char str[] = "-1.79779e+308"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == -HUGE_VAL); + } ios.imbue(std::locale(std::locale(), new my_numpunct)); { v = -1; diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp index 9138894784ed..d01f63d5920d 100644 --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp @@ -32,6 +32,7 @@ public: : F(refs) {} }; + int main() { const my_facet f(1); @@ -168,4 +169,29 @@ int main() assert(err == ios.goodbit); assert(std::isnan(v)); } + { + v = -1; + const char str[] = "3.40283e+39"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == HUGE_VALF); + } + { + v = -1; + const char str[] = "-3.40283e+38"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == -HUGE_VALF); + + } } diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp index 8e89ebc470cf..b79650b0199b 100644 --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp @@ -32,6 +32,7 @@ public: : F(refs) {} }; + int main() { const my_facet f(1); @@ -228,4 +229,28 @@ int main() assert(err != ios.failbit); assert(v == 304888344611713860501504000000.0L); } + { + v = -1; + const char str[] = "1.19973e+4933"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == HUGE_VALL); + } + { + v = -1; + const char str[] = "-1.18974e+4932"; // unrepresentable + std::ios_base::iostate err = ios.goodbit; + input_iterator<const char*> iter = + f.get(input_iterator<const char*>(str), + input_iterator<const char*>(str+sizeof(str)), + ios, err, v); + assert(iter.base() == str+sizeof(str)-1); + assert(err == ios.failbit); + assert(v == -HUGE_VALL); + } } diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html index bda4668839a5..fb25cf35f6b3 100644 --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -163,7 +163,7 @@ <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#2482">2482</td><td>[c.strings] Table 73 mentions nonexistent functions</td><td>Lenexa</td><td>Complete</td></tr> <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#2488">2488</td><td>Placeholders should be allowed and encouraged to be constexpr</td><td>Lenexa</td><td></td></tr> <tr><td></td><td></td><td></td><td></td></tr> - <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#1169">1169</a></td><td><tt>num_get</tt> not fully compatible with <tt>strto*</tt></td><td>Kona</td><td></td></tr> + <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#1169">1169</a></td><td><tt>num_get</tt> not fully compatible with <tt>strto*</tt></td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#2072">2072</a></td><td>Unclear wording about capacity of temporary buffers</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#2101">2101</a></td><td>Some transformation types can produce impossible types</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://cplusplus.github.io/LWG/lwg-defects.html#2111">2111</a></td><td>Which <tt>unexpected</tt>/<tt>terminate</tt> handler is called from the exception handling runtime?</td><td>Kona</td><td>Complete</td></tr>