diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 3c4a13332661e..597d0ddf3ff29 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -152,7 +152,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_string_view`` ``201606L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_to_chars`` *unimplemented* + ``__cpp_lib_to_chars`` ``201611L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_transparent_operators`` ``201510L`` ---------------------------------------------------------- ----------------- @@ -490,7 +490,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_text_encoding`` *unimplemented* ---------------------------------------------------------- ----------------- - ``__cpp_lib_to_chars`` *unimplemented* + ``__cpp_lib_to_chars`` ``202306L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_to_string`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index 9039c6f046445..89c803d3b836b 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -38,7 +38,11 @@ What's New in Libc++ 20.0.0? Implemented Papers ------------------ +- P0067R5: Elementary string conversions is implemented for platforms + where ``long double`` has the same format as ``double`` (`Github `__) - P0619R4: Reviewing Deprecated Facilities of C++17 for C++20 (`Github `__) +- P0682R1: Repairing elementary string conversions is implemented for platforms + where ``long double`` has the same format as ``double`` (`Github `__) - P2747R2: ``constexpr`` placement new (`Github `__) - P2609R3: Relaxing Ranges Just A Smidge (`Github `__) - P2985R0: A type trait for detecting virtual base classes (`Github `__) diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv index a589207085d36..69f6ccc1db984 100644 --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -71,7 +71,7 @@ "`P0394R4 `__","Hotel Parallelifornia: terminate() for Parallel Algorithms Exception Handling","2016-06 (Oulu)","|Complete|","17","" "","","","","","" "`P0003R5 `__","Removing Deprecated Exception Specifications from C++17","2016-11 (Issaquah)","|Complete|","5","" -"`P0067R5 `__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","For integer types, ``std::(to|from)_chars`` has been available since v7; for ``float`` and ``double``, ``std::to_chars`` since v14 and ``std::from_chars`` since v20. Support is complete except for ``long double``." +"`P0067R5 `__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","For integer types, ``std::(to|from)_chars`` has been available since v7; for ``float`` and ``double``, ``std::to_chars`` since v14 and ``std::from_chars`` since v20. Support is complete except for ``long double`` on platforms where its format is different ``double``." "`P0403R1 `__","Literal suffixes for ``basic_string_view``\ ","2016-11 (Issaquah)","|Complete|","4","" "`P0414R2 `__","Merging shared_ptr changes from Library Fundamentals to C++17","2016-11 (Issaquah)","|Complete|","11","" "`P0418R2 `__","Fail or succeed: there is no atomic lattice","2016-11 (Issaquah)","","","" @@ -109,5 +109,5 @@ "`P0618R0 `__","Deprecating ","2017-02 (Kona)","|Complete|","15","" "`P0623R0 `__","Final C++17 Parallel Algorithms Fixes","2017-02 (Kona)","|Nothing To Do|","","" "","","","","","" -"`P0682R1 `__","Repairing elementary string conversions","2017-07 (Toronto)","","","" +"`P0682R1 `__","Repairing elementary string conversions","2017-07 (Toronto)","|Partial|","","Support is complete in v20 on platforms where ``long double`` has the same format as ``double``." "`P0739R0 `__","Some improvements to class template argument deduction integration into the standard library","2017-07 (Toronto)","|Complete|","5","" diff --git a/libcxx/include/__charconv/from_chars_floating_point.h b/libcxx/include/__charconv/from_chars_floating_point.h index 811e518a81db7..063560d429a6f 100644 --- a/libcxx/include/__charconv/from_chars_floating_point.h +++ b/libcxx/include/__charconv/from_chars_floating_point.h @@ -64,6 +64,18 @@ from_chars(const char* __first, const char* __last, double& __value, chars_forma return std::__from_chars(__first, __last, __value, __fmt); } +# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE +_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result +from_chars(const char* __first, const char* __last, long double& __value, chars_format __fmt = chars_format::general) { + double __dval; + const auto __result = std::__from_chars(__first, __last, __dval, __fmt); + if (__result.ec != errc::invalid_argument) + __value = __dval; + return __result; +} +// TODO: Complete the implementation for platforms where long double has a different format from double. +# endif + #endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__config b/libcxx/include/__config index 9db00cd0c9fb9..8e8759a073e74 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1231,6 +1231,12 @@ typedef __char32_t char32_t; # define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0 # endif +# if defined(_MSC_VER) || __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__ +# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 1 +# else +# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 0 +# endif + #endif // __cplusplus #endif // _LIBCPP___CONFIG diff --git a/libcxx/include/version b/libcxx/include/version index fc57aeade9daf..c57f391e3f5dc 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -357,7 +357,9 @@ __cpp_lib_void_t 201411L # define __cpp_lib_shared_ptr_arrays 201611L # define __cpp_lib_shared_ptr_weak_type 201606L # define __cpp_lib_string_view 201606L -// # define __cpp_lib_to_chars 201611L +# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE +# define __cpp_lib_to_chars 201611L +# endif # undef __cpp_lib_transparent_operators # define __cpp_lib_transparent_operators 201510L # define __cpp_lib_type_trait_variable_templates 201510L @@ -572,8 +574,10 @@ __cpp_lib_void_t 201411L # define __cpp_lib_string_view 202403L // # define __cpp_lib_submdspan 202306L // # define __cpp_lib_text_encoding 202306L +# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE # undef __cpp_lib_to_chars -// # define __cpp_lib_to_chars 202306L +# define __cpp_lib_to_chars 202306L +# endif // # define __cpp_lib_to_string 202306L # undef __cpp_lib_tuple_like // # define __cpp_lib_tuple_like 202311L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp index cc38cbacd51b7..cd83a5740c5fb 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp @@ -50,16 +50,16 @@ # error "__cpp_lib_constexpr_charconv should not be defined before c++23" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++17" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++17" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -69,16 +69,16 @@ # error "__cpp_lib_constexpr_charconv should not be defined before c++23" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++20" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++20" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -91,16 +91,16 @@ # error "__cpp_lib_constexpr_charconv should have the value 202207L in c++23" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++23" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++23" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -113,16 +113,16 @@ # error "__cpp_lib_constexpr_charconv should have the value 202207L in c++26" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++26" # endif # if __cpp_lib_to_chars != 202306L # error "__cpp_lib_to_chars should have the value 202306L in c++26" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index b0f8b2f80067d..215a9ecd4a83e 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -3081,16 +3081,16 @@ # error "__cpp_lib_to_array should not be defined before c++20" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++17" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++17" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -4471,16 +4471,16 @@ # error "__cpp_lib_to_array should have the value 201907L in c++20" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++20" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++20" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -6077,16 +6077,16 @@ # error "__cpp_lib_to_array should have the value 201907L in c++23" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++23" # endif # if __cpp_lib_to_chars != 201611L # error "__cpp_lib_to_chars should have the value 201611L in c++23" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif @@ -8007,16 +8007,16 @@ # error "__cpp_lib_to_array should have the value 201907L in c++26" # endif -# if !defined(_LIBCPP_VERSION) +# if defined(TEST_LONG_DOUBLE_IS_DOUBLE) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++26" # endif # if __cpp_lib_to_chars != 202306L # error "__cpp_lib_to_chars should have the value 202306L in c++26" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_to_chars -# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!" # endif # endif diff --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp index 6faf0499c4c9b..95b04214aa882 100644 --- a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp +++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp @@ -15,6 +15,9 @@ // // from_chars_result from_chars(const char* first, const char* last, // double& value, chars_format fmt = chars_format::general) +// +// from_chars_result from_chars(const char* first, const char* last, +// long double& value, chars_format fmt = chars_format::general) #include #include @@ -1518,6 +1521,25 @@ struct test_hex { // test/std/utilities/charconv/charconv.msvc/test.cpp // uses random values. This tests contains errors found by this test. void test_random_errors() { +#ifdef TEST_LONG_DOUBLE_IS_DOUBLE + { + const char* s = "4.219902180869891e-2788"; + const char* last = s + std::strlen(s) - 1; + + // last + 1 contains a digit. When that value is parsed the exponent is + // e-2788 which returns std::errc::result_out_of_range and the value 0. + // the proper exponent is e-278, which can be represented by a + // long double whose format is same as double. + + long double value = 0.25L; + std::from_chars_result result = std::from_chars(s, last, value); + + assert(result.ec == std::errc{}); + assert(result.ptr == last); + assert(value == 4.219902180869891e-278L); + } + // TODO: Add more precise cases when the implementation for long double is complete. +#endif { const char* s = "4.219902180869891e-2788"; const char* last = s + std::strlen(s) - 1; diff --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h index fcae09478457b..0ae7a66f42173 100644 --- a/libcxx/test/support/charconv_test_helpers.h +++ b/libcxx/test/support/charconv_test_helpers.h @@ -317,7 +317,11 @@ auto all_unsigned = type_list< >(); auto integrals = concat(all_signed, all_unsigned); -auto all_floats = type_list< float, double >(); //TODO: Add long double +#ifdef TEST_LONG_DOUBLE_IS_DOUBLE // TODO: Remove this condition when the implementation for long double is complete. +auto all_floats = type_list< float, double, long double >(); +#else +auto all_floats = type_list< float, double >(); +#endif template