Index: libcxx/docs/Cxx2aStatusPaperStatus.csv =================================================================== --- libcxx/docs/Cxx2aStatusPaperStatus.csv +++ libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -115,7 +115,7 @@ "`P1208 `__","LWG","Adopt source_location for C++20","Cologne","","" "`P1355 `__","LWG","Exposing a narrow contract for ceil2","Cologne","|Complete|","9.0" "`P1361 `__","LWG","Integration of chrono with text formatting","Cologne","","" -"`P1423 `__","LWG","char8_t backward compatibility remediation","Cologne","","" +"`P1423 `__","LWG","char8_t backward compatibility remediation","Cologne","|In Progress|","" "`P1424 `__","LWG","'constexpr' feature macro concerns","Cologne","","" "`P1466 `__","LWG","Miscellaneous minor fixes for chrono","Cologne","","" "`P1474 `__","LWG","Helpful pointers for ContiguousIterator","Cologne","","" Index: libcxx/docs/ReleaseNotes.rst =================================================================== --- libcxx/docs/ReleaseNotes.rst +++ libcxx/docs/ReleaseNotes.rst @@ -56,3 +56,9 @@ - ``ceil2`` has been renamed to ``bit_ceil`` - ``floor2`` has been renamed to ``bit_floor`` - ``log2p1`` has been renamed to ``bit_width`` + +- In C++20 mode, ``std::filesystem::path::u8string()`` and + ``generic_u8string()`` now return ``std::u8string`` according to P0428, + while they return ``std::string`` in C++17. This can cause source + incompatibility, which is discussed and acknowledged in P1423, but that + paper doesn't suggest any remediation for this incompatibility. Index: libcxx/include/__config =================================================================== --- libcxx/include/__config +++ libcxx/include/__config @@ -989,6 +989,12 @@ # define _LIBCPP_DEPRECATED_IN_CXX20 #endif +#if !defined(_LIBCPP_NO_HAS_CHAR8_T) +# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED +#else +# define _LIBCPP_DEPRECATED_WITH_CHAR8_T +#endif + // Macros to enter and leave a state where deprecation warnings are suppressed. #if !defined(_LIBCPP_SUPPRESS_DEPRECATED_PUSH) && \ (defined(_LIBCPP_COMPILER_CLANG) || defined(_LIBCPP_COMPILER_GCC)) Index: libcxx/include/filesystem =================================================================== --- libcxx/include/filesystem +++ libcxx/include/filesystem @@ -547,6 +547,13 @@ static const bool value = true; using __char_type = wchar_t; }; +#ifndef _LIBCPP_NO_HAS_CHAR8_T +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char8_t; +}; +#endif template <> struct __can_convert_char { static const bool value = true; @@ -995,7 +1002,11 @@ _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; } _LIBCPP_INLINE_VISIBILITY _VSTD::string string() const { return __pn_; } +#ifndef _LIBCPP_NO_HAS_CHAR8_T + _LIBCPP_INLINE_VISIBILITY _VSTD::u8string u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); } +#else _LIBCPP_INLINE_VISIBILITY _VSTD::string u8string() const { return __pn_; } +#endif #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) template , @@ -1023,7 +1034,11 @@ // generic format observers _VSTD::string generic_string() const { return __pn_; } +#ifndef _LIBCPP_NO_HAS_CHAR8_T + _VSTD::u8string generic_u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); } +#else _VSTD::string generic_u8string() const { return __pn_; } +#endif #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) template , @@ -1213,23 +1228,37 @@ size_t hash_value(const path& __p) noexcept; template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T typename enable_if<__is_pathable<_Source>::value, path>::type u8path(const _Source& __s) { static_assert( +#ifndef _LIBCPP_NO_HAS_CHAR8_T + is_same::__char_type, char8_t>::value || +#endif is_same::__char_type, char>::value, "u8path(Source const&) requires Source have a character type of type " - "'char'"); + "'char'" +#ifndef _LIBCPP_NO_HAS_CHAR8_T + " or 'char8_t'" +#endif + ); return path(__s); } template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T typename enable_if<__is_pathable<_InputIt>::value, path>::type u8path(_InputIt __f, _InputIt __l) { static_assert( +#ifndef _LIBCPP_NO_HAS_CHAR8_T + is_same::__char_type, char8_t>::value || +#endif is_same::__char_type, char>::value, - "u8path(Iter, Iter) requires Iter have a value_type of type 'char'"); + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" +#ifndef _LIBCPP_NO_HAS_CHAR8_T + " or 'char8_t'" +#endif + ); return path(__f, __l); } Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp @@ -125,6 +125,9 @@ int main(int, char**) { for (auto const& MS : PathList) { RunTestCase(MS); +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) + RunTestCase(MS); +#endif RunTestCase(MS); RunTestCase(MS); RunTestCase(MS); Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp @@ -45,8 +45,15 @@ assert(s == value); } { +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) + ASSERT_SAME_TYPE(decltype(p.generic_u8string()), std::u8string); + std::u8string s = p.generic_u8string(); + assert(s == (const char8_t*)MS); +#else + ASSERT_SAME_TYPE(decltype(p.generic_u8string()), std::string); std::string s = p.generic_u8string(); assert(s == (const char*)MS); +#endif } { std::wstring s = p.generic_wstring(); Index: libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp @@ -46,8 +46,15 @@ assert(s == value); } { +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) + ASSERT_SAME_TYPE(decltype(p.u8string()), std::u8string); + std::u8string s = p.u8string(); + assert(s == (const char8_t*)MS); +#else + ASSERT_SAME_TYPE(decltype(p.u8string()), std::string); std::string s = p.u8string(); assert(s == (const char*)MS); +#endif } { std::wstring s = p.wstring(); Index: libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS // @@ -48,6 +49,29 @@ path p = fs::u8path(In3, In3End); assert(p == In1); } +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) && defined(_LIBCPP_VERSION) + const char8_t* u8In1 = u8"abcd/efg"; + const std::u8string u8In2(u8In1); + const auto u8In3 = u8In2.begin(); + const auto u8In3End = u8In2.end(); + // Proposed in P1423, marked tested only for libc++ + { + path p = fs::u8path(u8In1); + assert(p == In1); + } + { + path p = fs::u8path(u8In2); + assert(p == In1); + } + { + path p = fs::u8path(u8In3); + assert(p == In1); + } + { + path p = fs::u8path(u8In3, u8In3End); + assert(p == In1); + } +#endif return 0; } Index: libcxx/test/support/filesystem_test_helper.h =================================================================== --- libcxx/test/support/filesystem_test_helper.h +++ libcxx/test/support/filesystem_test_helper.h @@ -430,16 +430,28 @@ // Misc test types -#define MKSTR(Str) {Str, TEST_CONCAT(L, Str), TEST_CONCAT(u, Str), TEST_CONCAT(U, Str)} +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) +#define CHAR8_ONLY(x) x, +#else +#define CHAR8_ONLY(x) +#endif + +#define MKSTR(Str) {Str, TEST_CONCAT(L, Str), CHAR8_ONLY(TEST_CONCAT(u8, Str)) TEST_CONCAT(u, Str), TEST_CONCAT(U, Str)} struct MultiStringType { const char* s; const wchar_t* w; +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) + const char8_t* u8; +#endif const char16_t* u16; const char32_t* u32; operator const char* () const { return s; } operator const wchar_t* () const { return w; } +#if TEST_STD_VER > 17 && defined(__cpp_char8_t) + operator const char8_t* () const { return u8; } +#endif operator const char16_t* () const { return u16; } operator const char32_t* () const { return u32; } };