[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