[libcxx-commits] [libcxx] 6be11e3 - [libcxx] Implement c++2a char8_t input/output of std::filesystem::path
Martin Storsjö via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 4 01:43:29 PST 2020
Author: Martin Storsjö
Date: 2020-12-04T11:37:05+02:00
New Revision: 6be11e35d5397ae1c117eb840a969585fdd7d08d
URL: https://github.com/llvm/llvm-project/commit/6be11e35d5397ae1c117eb840a969585fdd7d08d
DIFF: https://github.com/llvm/llvm-project/commit/6be11e35d5397ae1c117eb840a969585fdd7d08d.diff
LOG: [libcxx] Implement c++2a char8_t input/output of std::filesystem::path
This implements the std::filesystem parts of P0482 (which is already
marked as in progress), and applies the actions that are suggested
in P1423.
Differential Revision: https://reviews.llvm.org/D90222
Added:
Modified:
libcxx/docs/Cxx2aStatusPaperStatus.csv
libcxx/docs/ReleaseNotes.rst
libcxx/include/__config
libcxx/include/filesystem
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.generic.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.nonmember/path.factory.pass.cpp
libcxx/test/support/filesystem_test_helper.h
Removed:
################################################################################
diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv
index 88d5641403f5..ac2c093cea3d 100644
--- a/libcxx/docs/Cxx2aStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv
@@ -115,7 +115,7 @@
"`P1208 <https://wg21.link/P1208>`__","LWG","Adopt source_location for C++20","Cologne","",""
"`P1355 <https://wg21.link/P1355>`__","LWG","Exposing a narrow contract for ceil2","Cologne","|Complete|","9.0"
"`P1361 <https://wg21.link/P1361>`__","LWG","Integration of chrono with text formatting","Cologne","",""
-"`P1423 <https://wg21.link/P1423>`__","LWG","char8_t backward compatibility remediation","Cologne","",""
+"`P1423 <https://wg21.link/P1423>`__","LWG","char8_t backward compatibility remediation","Cologne","|In Progress|",""
"`P1424 <https://wg21.link/P1424>`__","LWG","'constexpr' feature macro concerns","Cologne","Superseded by `P1902 <https://wg21.link/P1902>`__",""
"`P1466 <https://wg21.link/P1466>`__","LWG","Miscellaneous minor fixes for chrono","Cologne","",""
"`P1474 <https://wg21.link/P1474>`__","LWG","Helpful pointers for ContiguousIterator","Cologne","",""
diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 719115fded67..8ce9b2961119 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -56,3 +56,9 @@ API Changes
- ``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.
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 1a206680ecdc..3f56a022177d 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -989,6 +989,12 @@ typedef unsigned int char32_t;
# 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))
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
index b4a64768500d..d24751b716e3 100644
--- a/libcxx/include/filesystem
+++ b/libcxx/include/filesystem
@@ -547,6 +547,13 @@ struct __can_convert_char<wchar_t> {
static const bool value = true;
using __char_type = wchar_t;
};
+#ifndef _LIBCPP_NO_HAS_CHAR8_T
+template <>
+struct __can_convert_char<char8_t> {
+ static const bool value = true;
+ using __char_type = char8_t;
+};
+#endif
template <>
struct __can_convert_char<char16_t> {
static const bool value = true;
@@ -995,7 +1002,11 @@ public:
_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 <class _ECharT, class _Traits = char_traits<_ECharT>,
@@ -1023,7 +1034,11 @@ public:
// 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 <class _ECharT, class _Traits = char_traits<_ECharT>,
@@ -1213,23 +1228,37 @@ _LIBCPP_FUNC_VIS
size_t hash_value(const path& __p) noexcept;
template <class _Source>
-_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<typename __is_pathable<_Source>::__char_type, char8_t>::value ||
+#endif
is_same<typename __is_pathable<_Source>::__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 <class _InputIt>
-_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<typename __is_pathable<_InputIt>::__char_type, char8_t>::value ||
+#endif
is_same<typename __is_pathable<_InputIt>::__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);
}
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp
index 9e4a882186d1..83ce692e7280 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source.pass.cpp
@@ -123,6 +123,9 @@ void test_sfinae() {
int main(int, char**) {
for (auto const& MS : PathList) {
RunTestCase<char>(MS);
+#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
+ RunTestCase<char8_t>(MS);
+#endif
RunTestCase<wchar_t>(MS);
RunTestCase<char16_t>(MS);
RunTestCase<char32_t>(MS);
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
index bd32eda4c351..58c07e2feb70 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
@@ -45,8 +45,15 @@ int main(int, char**)
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();
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp
index 12cda192b8e8..05075a31c013 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.native.obs/named_overloads.pass.cpp
@@ -46,8 +46,15 @@ int main(int, char**)
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();
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp
index b245f28e6e57..9df81f4c6ae0 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.nonmember/path.factory.pass.cpp
+++ b/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
// <filesystem>
@@ -48,6 +49,29 @@ int main(int, char**)
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;
}
diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
index 81366580db89..eeee3e935b8a 100644
--- a/libcxx/test/support/filesystem_test_helper.h
+++ b/libcxx/test/support/filesystem_test_helper.h
@@ -430,16 +430,28 @@ struct CWDGuard {
// 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; }
};
More information about the libcxx-commits
mailing list