On 29/11/19 17:45 +0000, Jonathan Wakely wrote:
On 15/09/19 15:39 -0400, Tom Honermann wrote:
This series of patches provides an implementation of the changes for C++ proposal P1423R3 [1].

These changes do not impact default libstdc++ behavior for C++17 and earlier; they are only active for C++2a or when the -fchar8_t option is specified.

Tested x86_64-linux.

Patch 1: Decouple constraints for u8path from path constructors.
Patch 2: Update __cpp_lib_char8_t feature test macro value, add deleted operators, update u8path.
Patch 3: Updates to existing tests.
Patch 4: New tests.

Tom.

[1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1423r3.html

It took a while, but I've committed these four patches, with just some
minor whitespace changes and changelog tweaks.

Running the new tests revealed a latent bug on Windows, where
experimental::filesystem::u8path(const Source&) assumed the input
was an iterator over a NTCTS. That worked for a const char* but not a
std::string or experimental::string_view.

The attached patch fixes that (and simplifies the #if and if-constexpr
conditions for Windows) but there's a remaining bug. Constructing a
experimental::filesystem::path from a char8_t string doesn't do the
right thing on Windows, so these cases fails:

 fs::path p(u8"\xf0\x9d\x84\x9e");
 VERIFY( p.u8string() == u8"\U0001D11E" );

 p = fs::u8path(u8"\xf0\x9d\x84\x9e");
 VERIFY( p.u8string() == u8"\U0001D11E" );

It works correctly for std::filesystem::path, just not the TS version.

I plan to commit the attached patch after some more testing. I'll
backport something like it too.


commit f9ff56e4624c34be0615aab62ed4a2ce559dd567
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Fri Nov 29 19:36:39 2019 +0000

    libstdc++: Fix experimental::filesystem::u8path(const Source&) for Windows
    
    This function failed to compile when called with a std::string.
    
            * include/bits/fs_path.h (u8path(InputIterator, InputIterator))
            (u8path(const Source&)) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Simplify
            conditions.
            * include/experimental/bits/fs_path.h (__u8path(const Source&, char)):
            Add overloads for std::string and types convertible to std::string.

diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index b129372447b..20ec42da57d 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -691,14 +691,8 @@ namespace __detail
     u8path(_InputIterator __first, _InputIterator __last)
     {
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-#ifdef _GLIBCXX_USE_CHAR8_T
-      if constexpr (is_same_v<_CharT, char8_t>)
+      if constexpr (is_same_v<_CharT, char>)
 	{
-	  return path{ __first, __last };
-	}
-      else
-	{
-#endif
 	  // XXX This assumes native wide encoding is UTF-16.
 	  std::codecvt_utf8_utf16<path::value_type> __cvt;
 	  path::string_type __tmp;
@@ -710,16 +704,16 @@ namespace __detail
 	  else
 	    {
 	      const std::string __u8str{__first, __last};
-	      const char* const __ptr = __u8str.data();
-	      if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
+	      const char* const __p = __u8str.data();
+	      if (__str_codecvt_in_all(__p, __p + __u8str.size(), __tmp, __cvt))
 		return path{ __tmp };
 	    }
 	  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
-#ifdef _GLIBCXX_USE_CHAR8_T
 	}
-#endif
+      else
+	return path{ __first, __last };
 #else
       // This assumes native normal encoding is UTF-8.
       return path{ __first, __last };
@@ -737,14 +731,8 @@ namespace __detail
     u8path(const _Source& __source)
     {
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-#ifdef _GLIBCXX_USE_CHAR8_T
-      if constexpr (is_same_v<_CharT, char8_t>)
+      if constexpr (is_same_v<_CharT, char>)
 	{
-	  return path{ __source };
-	}
-      else
-	{
-#endif
 	  if constexpr (is_convertible_v<const _Source&, std::string_view>)
 	    {
 	      const std::string_view __s = __source;
@@ -755,9 +743,9 @@ namespace __detail
 	      std::string __s = path::_S_string_from_iter(__source);
 	      return filesystem::u8path(__s.data(), __s.data() + __s.size());
 	    }
-#ifdef _GLIBCXX_USE_CHAR8_T
 	}
-#endif
+      else
+	return path{ __source };
 #else
       return path{ __source };
 #endif
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 91202e5b008..796458b37b0 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -644,8 +644,22 @@ namespace __detail
 
   /// Create a path from a UTF-8-encoded sequence of char
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  inline path
+  __u8path(const string& __s, char)
+  {
+    return filesystem::u8path(__s.data(), __s.data() + __s.size());
+  }
+
   template<typename _Source>
-    inline path
+    inline __enable_if_t<is_convertible<const _Source&, string>::value, path>
+    __u8path(const _Source& __source, char)
+    {
+      std::string __s = __source;
+      return filesystem::u8path(__s.data(), __s.data() + __s.size());
+    }
+
+  template<typename _Source>
+    inline __enable_if_t<!is_convertible<const _Source&, string>::value, path>
     __u8path(const _Source& __source, char)
     {
       std::string __s = path::_S_string_from_iter(__source);

Reply via email to