[PATCH] PR libstdc++/78870 support std::filesystem on Windows

Jonathan Wakely jwakely@redhat.com
Thu May 31 19:20:00 GMT 2018


This adds incomplete but functional support for std::filesystem and
std::experimental::filesystem on MinGW. In theory there should be no
changes to the existing behaviour for POSIX targets from this patch,
as all the various bugs I found while working on this have already
been fixed in separate patches.

Tested powerpc64le-linux, and x86_64-w64-mingw32 (with a few expected
FAILures on mingw-w64). Committed to trunk.


-------------- next part --------------
commit c5a8ea40f82117e98784b0342c2d873a97d990ef
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 31 16:37:44 2018 +0100

    PR libstdc++/78870 support std::filesystem on Windows
    
            PR libstdc++/78870 support std::filesystem on Windows
            * config.h.in: Regenerate.
            * configure: Regenerate.
            * configure.ac: Check for link, readlink and symlink.
            * include/bits/fs_path.h (path::operator/=(const path&)): Move
            definition out of class body.
            (path::is_absolute(), path::_M_append(path)): Likewise.
            (operator<<(basic_ostream, const path&)): Use std::quoted directly.
            (operator>>(basic_istream, path&)): Likewise.
            (u8path): Reorder definitions and fix Windows implementation.
            (path::is_absolute()): Define inline and fix for Windows.
            [!_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
            Define POSIX version inline.
            (path::_M_append(path)): Define inline.
            * include/experimental/bits/fs_path.h (path::is_absolute()): Move
            definition out of class body.
            (operator<<(basic_ostream, const path&)): Fix type of delimiter and
            escape characters.
            (operator>>(basic_istream, path&)): Likewise.
            (path::is_absolute()): Define inline and fix for Windows.
            * src/filesystem/dir-common.h (__gnu_posix): New namespace.
            (__gnu_posix::char_type, __gnu_posix::DIR, __gnu_posix::dirent)
            (__gnu_posix::opendir, __gnu_posix::readdir, __gnu_posix::closedir):
            Define as adaptors for Windows functions/types or as
            using-declarations for POSIX functions/types.
            (_Dir_base, get_file_type): Qualify names to use declarations from
            __gnu_posix namespace.
            (_Dir_base::is_dor_or_dotdot): New helper functions.
            * src/filesystem/dir.cc (_Dir, recursive_directory_iterator): Qualify
            names to use declarations from __gnu_posix namespace.
            * src/filesystem/ops-common.h (__gnu_posix): New nested namespace.
            (__gnu_posix::open, __gnu_posix::close, __gnu_posix::stat_type)
            (__gnu_posix::stat, __gnu_posix::lstat, __gnu_posix::mode_t)
            (__gnu_posix::chmod, __gnu_posix::mkdir, __gnu_posix::getcwd)
            (__gnu_posix::chdir, __gnu_posix::utimbuf, __gnu_posix::utime)
            (__gnu_posix::rename, __gnu_posix::truncate, __gnu_posix::char_type):
            Define as adaptors for Windows functions/types or as
            using-declarations for POSIX functions/types.
            (stat_type, do_copy_file): Qualify names to use declarations from
            __gnu_posix namespace.
            (do_space): Declare new function.
            (make_file_type): Only use S_ISLNK if defined.
            * src/filesystem/ops.cc (char_ptr, filesystem::canonical): Use
            path::value_type not char.
            (filesystem::copy, create_dir, filesystem::create_directory): Qualify
            names to use declarations from __gnu_posix namespace.
            (filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
            add implementation for Windows.
            (filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
            (filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
            [!_PC_PATH_MAX]: Don't use pathconf.
            [PATH_MAX]: Use if defined.
            (filesystem::current_path(const path&, error_code&))
            (filesystem::equivalent, do_stat, filesystem::hard_link_count)
            (filesystem::last_write_time, filesystem::permissions): Use names
            from __gnu_posix.
            (filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
            (filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
            implementation for Windows.
            (filesystem::rename, filesystem::resize_file): Use names from
            __gnu_posix.
            (filesystem::space): Use do_space.
            [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Get absolute path to directory.
            (filesystem::status, filesystem::symlink_status): Use names from
            __gnu_posix.
            (filesystem::temp_directory_path): Add implementation for Windows.
            * src/filesystem/path.cc (dot): Define constant.
            (path::replace_extension): Use dot.
            (path::_M_find_extension): Likewise. Use path::string_type not
            std::string.
            (path::_M_split_cmpts): Use dot.
            (filesystem_error::_M_get_what): Use u8string() not native().
            * src/filesystem/std-dir.cc (_Dir, recursive_directory_iterator):
            Qualify names to use declarations from __gnu_posix namespace.
            * src/filesystem/std-ops.cc (filesystem::absolute(const path&)): Use
            correct error_code.
            (filesystem::absolute(const path&, error_code&)): Add implementation
            for Windows.
            (char_ptr, filesystem::canonical): Use path::value_type not char.
            (do_copy_file): Use names from __gnu_posix.
            [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Do not use fchmod, fchmodat or
            sendfile.
            (filesystem::copy, create_dir, filesystem::create_directory): Qualify
            names to use declarations from __gnu_posix namespace.
            (filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
            add implementation for Windows.
            (filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
            (filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
            [!_PC_PATH_MAX]: Don't use pathconf.
            [PATH_MAX]: Use if defined.
            (filesystem::current_path(const path&, error_code&))
            (filesystem::equivalent, do_stat, filesystem::hard_link_count)
            (filesystem::last_write_time, filesystem::permissions): Use names
            from __gnu_posix.
            (filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
            (filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
            implementation for Windows.
            (filesystem::rename, filesystem::resize_file): Use names from
            __gnu_posix.
            (do_space): Define.
            (filesystem::space): Use do_space.
            (filesystem::status, filesystem::symlink_status): Use names from
            __gnu_posix.
            (filesystem::temp_directory_path): Add implementation for Windows.
            * src/filesystem/std-path.cc
            [_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
            Define for Windows.
            (dot): Define constant.
            (path::replace_extension, is_dot): Use dot.
            (path::lexically_normal): Check _M_type instead of calling
            non-existent function.
            (path::_M_find_extension): Use dot. Use path::string_type not
            std::string.
            (path::_M_split_cmpts): Use dot.
            (filesystem_error::_M_get_what): Use u8string() not native().
            * testsuite/27_io/filesystem/iterators/directory_iterator.cc: Do not
            use symlinks.
            * testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
            Likewise.
            * testsuite/27_io/filesystem/operations/absolute.cc: Use
            __gnu_test::root_path() instead of "/" and add Windows-specific tests.
            * testsuite/27_io/filesystem/operations/canonical.cc: Use
            path::string() to get narrow string, not path::native().
            * testsuite/27_io/filesystem/operations/copy.cc: Construct fstreams
            with std::filesystem::path not std::basic_string.
            * testsuite/27_io/filesystem/operations/copy_file.cc: Likewise.
            * testsuite/27_io/filesystem/operations/exists.cc: Use
            __gnu_test::root_path() instead of "/".
            * testsuite/27_io/filesystem/operations/is_empty.cc: Construct
            fstreams with std::filesystem::path not std::basic_string.
            * testsuite/27_io/filesystem/operations/last_write_time.cc: Use
            path::string() to get narrow string.
            * testsuite/27_io/filesystem/operations/space.cc: Check results for
            errors, expect sensible values otherwise.
            * testsuite/27_io/filesystem/operations/temp_directory_path.cc: Add
            helpers for adjusting the environment on Windows.
            * testsuite/27_io/filesystem/path/append/path.cc: Test
            Windows-specific behaviour.
            * testsuite/27_io/filesystem/path/construct/format.cc: Fix creation
            of path::string_type objects.
            * testsuite/27_io/filesystem/path/construct/locale.cc: Compare native
            string to wide string on Windows.
            * testsuite/27_io/filesystem/path/decompose/root_directory.cc: Allow
            for backslash as root-directory.
            * testsuite/27_io/filesystem/path/decompose/stem.cc: Use
            path::string() to get narrow string.
            * testsuite/27_io/filesystem/path/itr/traversal.cc: Test Windows-style
            paths.
            * testsuite/27_io/filesystem/path/native/string.cc: Use string_type
            not std::string.
            * testsuite/27_io/filesystem/path/query/is_absolute.cc: Adjust for
            different definintion of absolute paths on Windows.
            * testsuite/experimental/filesystem/iterators/directory_iterator.cc:
            Do not use symlinks.
            * testsuite/experimental/filesystem/operations/absolute.cc: Test
            Windows behaviour.
            * testsuite/experimental/filesystem/operations/copy.cc: Construct
            fstreams with NTCTS not std::basic_string.
            * testsuite/experimental/filesystem/operations/copy_file.cc: Likewise.
            * testsuite/experimental/filesystem/operations/exists.cc: Use
            __gnu_test::root_path() instead of "/".
            * testsuite/experimental/filesystem/operations/is_empty.cc: Construct
            fstreams with NTCTS not std::basic_string.
            * testsuite/experimental/filesystem/operations/last_write_time.cc:
            Use path::string() to get narrow string.
            * testsuite/experimental/filesystem/operations/space.cc: Use
            __gnu_test::root_path() instead of "/".
            * testsuite/experimental/filesystem/operations/temp_directory_path.cc:
            Add helpers for adjusting the environment on Windows.
            * testsuite/experimental/filesystem/path/append/path.cc: Use
            path::string() to get narrow strings for comparisons.
            * testsuite/experimental/filesystem/path/concat/path.cc: Likewise.
            * testsuite/experimental/filesystem/path/decompose/root_directory.cc:
            Likewise.
            * testsuite/experimental/filesystem/path/decompose/stem.cc: Likewise.
            * testsuite/experimental/filesystem/path/native/string.cc: Use
            string_type not std::string.
            * testsuite/experimental/filesystem/path/query/is_absolute.cc:
            Adjust for different definintion of absolute paths on Windows.
            * testsuite/util/testsuite_fs.h (__gnu_test::root_path()): New
            function.
            (__gnu_test::scoped_file): Construct fstreams with NTCTS not
            std::basic_string.

diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 7e1fd84606a..dde1c4da944 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -420,6 +420,7 @@ GLIBCXX_CHECK_GTHREADS
 
 # For Filesystem TS.
 AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
+AC_CHECK_FUNCS(link readlink symlink)
 GLIBCXX_ENABLE_FILESYSTEM_TS
 GLIBCXX_CHECK_FILESYSTEM_DEPS
 
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 2dbde74e0d4..6eab800ac56 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -37,11 +37,11 @@
 #include <vector>
 #include <locale>
 #include <iosfwd>
+#include <iomanip>
 #include <codecvt>
 #include <string_view>
 #include <system_error>
 #include <bits/stl_algobase.h>
-#include <bits/quoted_string.h>
 #include <bits/locale_conv.h>
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -232,37 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
     // appends
 
-    path& operator/=(const path& __p)
-    {
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-      if (__p.is_absolute()
-	  || (__p.has_root_name() && __p.root_name() != root_name()))
-	operator=(__p);
-      else
-	{
-	  string_type __pathname;
-	  if (__p.has_root_directory())
-	    __pathname = root_name().native();
-	  else if (has_filename() || (!has_root_directory() && is_absolute()))
-	    __pathname = _M_pathname + preferred_separator;
-	  __pathname += __p.relative_path().native(); // XXX is this right?
-	  _M_pathname.swap(__pathname);
-	  _M_split_cmpts();
-	}
-#else
-      // Much simpler, as any path with root-name or root-dir is absolute.
-      if (__p.is_absolute())
-	operator=(__p);
-      else
-	{
-	  if (has_filename() || (_M_type == _Type::_Root_name))
-	    _M_pathname += preferred_separator;
-	  _M_pathname += __p.native();
-	  _M_split_cmpts();
-	}
-#endif
-      return *this;
-    }
+    path& operator/=(const path& __p);
 
     template <class _Source>
       _Path<_Source>&
@@ -378,7 +348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     bool has_filename() const;
     bool has_stem() const;
     bool has_extension() const;
-    bool is_absolute() const { return has_root_directory(); }
+    bool is_absolute() const;
     bool is_relative() const { return !is_absolute(); }
 
     // generation
@@ -419,19 +389,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
     enum class _Split { _Stem, _Extension };
 
-    path&
-    _M_append(path __p)
-    {
-      if (__p.is_absolute())
-	operator=(std::move(__p));
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-      else if (__p.has_root_name() && __p.root_name() != root_name())
-	operator=(std::move(__p));
-#endif
-      else
-	operator/=(const_cast<const path&>(__p));
-      return *this;
-    }
+    path& _M_append(path __p);
 
     pair<const string_type*, size_t> _M_find_extension() const;
 
@@ -552,10 +510,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     basic_ostream<_CharT, _Traits>&
     operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
     {
-      auto __tmp = __p.string<_CharT, _Traits>();
-      using __quoted_string
-	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
-      __os << __quoted_string{__tmp, '"', '\\'};
+      __os << std::quoted(__p.string<_CharT, _Traits>());
       return __os;
     }
 
@@ -565,43 +520,58 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
     {
       basic_string<_CharT, _Traits> __tmp;
-      using __quoted_string
-	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
-      if (__is >> __quoted_string{ __tmp, '"', '\\' })
+      if (__is >> std::quoted(__tmp))
 	__p = std::move(__tmp);
       return __is;
     }
 
-  template<typename _Source>
-    inline auto
-    u8path(const _Source& __source)
-    -> decltype(filesystem::path(__source, std::locale::classic()))
-    {
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-      const std::string __u8str{__source};
-      return std::filesystem::u8path(__u8str.begin(), __u8str.end());
-#else
-      return path{ __source };
-#endif
-    }
-
   template<typename _InputIterator>
     inline auto
     u8path(_InputIterator __first, _InputIterator __last)
     -> decltype(filesystem::path(__first, __last, std::locale::classic()))
     {
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-      codecvt_utf8<value_type> __cvt;
-      string_type __tmp;
-      if (__str_codecvt_in(__first, __last, __tmp, __cvt))
-	return path{ __tmp };
+      codecvt_utf8<path::value_type> __cvt;
+      path::string_type __tmp;
+      if constexpr (is_pointer_v<_InputIterator>)
+	{
+	  if (__str_codecvt_in(__first, __last, __tmp, __cvt))
+	    return path{ __tmp };
+	}
       else
-	return {};
+	{
+	  const std::string __u8str{__first, __last};
+	  const char* const __ptr = __u8str.data();
+	  if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
+	    return path{ __tmp };
+	}
+      return {};
 #else
       return path{ __first, __last };
 #endif
     }
 
+  template<typename _Source>
+    inline auto
+    u8path(const _Source& __source)
+    -> decltype(filesystem::path(__source, std::locale::classic()))
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      if constexpr (is_convertible_v<const _Source&, std::string_view>)
+	{
+	  const std::string_view __s = __source;
+	  return filesystem::u8path(__s.data(), __s.data() + __s.size());
+	}
+      else
+	{
+	  std::string __s = path::_S_string_from_iter(__source);
+	  return filesystem::u8path(__s.data(), __s.data() + __s.size());
+	}
+#else
+      return path{ __source };
+#endif
+    }
+
   class filesystem_error : public std::system_error
   {
   public:
@@ -1068,6 +1038,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return ext.first && ext.second != string_type::npos;
   }
 
+  inline bool
+  path::is_absolute() const
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    return has_root_name() && has_root_directory();
+#else
+    return has_root_directory();
+#endif
+  }
+
   inline path::iterator
   path::begin() const
   {
@@ -1084,6 +1064,38 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return iterator(this, true);
   }
 
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  inline path& path::operator/=(const path& __p)
+  {
+    // Much simpler than the specification in the standard,
+    // as any path with root-name or root-dir is absolute.
+    if (__p.is_absolute())
+      operator=(__p);
+    else
+      {
+	if (has_filename() || (_M_type == _Type::_Root_name))
+	  _M_pathname += preferred_separator;
+	_M_pathname += __p.native();
+	_M_split_cmpts();
+      }
+    return *this;
+  }
+#endif
+
+  inline path&
+  path::_M_append(path __p)
+  {
+    if (__p.is_absolute())
+      operator=(std::move(__p));
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    else if (__p.has_root_name() && __p.root_name() != root_name())
+      operator=(std::move(__p));
+#endif
+    else
+      operator/=(const_cast<const path&>(__p));
+    return *this;
+  }
+
   inline path::iterator&
   path::iterator::operator++()
   {
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 3ce2cd95b73..653b4a3fe85 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -372,7 +372,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     bool has_filename() const;
     bool has_stem() const;
     bool has_extension() const;
-    bool is_absolute() const { return has_root_directory(); }
+    bool is_absolute() const;
     bool is_relative() const { return !is_absolute(); }
 
     // iterators
@@ -537,7 +537,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       auto __tmp = __p.string<_CharT, _Traits>();
       using __quoted_string
 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
-      __os << __quoted_string{__tmp, '"', '\\'};
+      __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')};
       return __os;
     }
 
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       basic_string<_CharT, _Traits> __tmp;
       using __quoted_string
 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
-      if (__is >> __quoted_string{ __tmp, '"', '\\' })
+      if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') })
 	__p = std::move(__tmp);
       return __is;
     }
@@ -993,6 +993,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return ext.first && ext.second != string_type::npos;
   }
 
+  inline bool
+  path::is_absolute() const
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    return has_root_name() && has_root_directory();
+#else
+    return has_root_directory();
+#endif
+  }
+
   inline path::iterator
   path::begin() const
   {
diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h
index 21ba01ca970..03875819d04 100644
--- a/libstdc++-v3/src/filesystem/dir-common.h
+++ b/libstdc++-v3/src/filesystem/dir-common.h
@@ -26,6 +26,9 @@
 #define _GLIBCXX_DIR_COMMON_H 1
 
 #include <string.h>  // strcmp
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+#include <wchar.h>  // wcscmp
+#endif
 #ifdef _GLIBCXX_HAVE_DIRENT_H
 # ifdef _GLIBCXX_HAVE_SYS_TYPES_H
 #  include <sys/types.h>
@@ -35,26 +38,42 @@
 # error "the <dirent.h> header is needed to build the Filesystem TS"
 #endif
 
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef opendir
-# define opendir _wopendir
-#endif
-
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 namespace filesystem
 {
+namespace __gnu_posix
+{
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
+using char_type = wchar_t;
+using DIR = ::_WDIR;
+using dirent = _wdirent;
+inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); }
+inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); }
+inline int closedir(DIR* dir) { return ::_wclosedir(dir); }
+#else
+using char_type = char;
+using DIR = ::DIR;
+typedef struct ::dirent dirent;
+using ::opendir;
+using ::readdir;
+using ::closedir;
+#endif
+} // namespace __gnu_posix
+
+namespace posix = __gnu_posix;
 
 struct _Dir_base
 {
-  _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { }
+  _Dir_base(posix::DIR* dirp = nullptr) : dirp(dirp) { }
 
   // If no error occurs then dirp is non-null,
   // otherwise null (whether error ignored or not).
-  _Dir_base(const char* p, bool skip_permission_denied,
+  _Dir_base(const posix::char_type* pathname, bool skip_permission_denied,
 	    error_code& ec) noexcept
-  : dirp(::opendir(p))
+  : dirp(posix::opendir(pathname))
   {
     if (dirp)
       ec.clear();
@@ -72,22 +91,22 @@ struct _Dir_base
 
   _Dir_base& operator=(_Dir_base&&) = delete;
 
-  ~_Dir_base() { if (dirp) ::closedir(dirp); }
+  ~_Dir_base() { if (dirp) posix::closedir(dirp); }
 
-  const struct ::dirent*
+  const posix::dirent*
   advance(bool skip_permission_denied, error_code& ec) noexcept
   {
     ec.clear();
 
     int err = std::exchange(errno, 0);
-    const struct ::dirent* entp = readdir(dirp);
+    const posix::dirent* entp = posix::readdir(dirp);
     // std::swap cannot be used with Bionic's errno
     err = std::exchange(errno, err);
 
     if (entp)
       {
 	// skip past dot and dot-dot
-	if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
+	if (is_dot_or_dotdot(entp->d_name))
 	  return advance(skip_permission_denied, ec);
 	return entp;
       }
@@ -105,15 +124,24 @@ struct _Dir_base
       }
   }
 
-  DIR*	dirp;
+  static bool is_dot_or_dotdot(const char* s) noexcept
+  { return !strcmp(s, ".") || !strcmp(s, ".."); }
+
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  static bool is_dot_or_dotdot(const wchar_t* s) noexcept
+  { return !wcscmp(s, L".") || !wcscmp(s, L".."); }
+#endif
+
+  posix::DIR*	dirp;
 };
 
 } // namespace filesystem
 
 // BEGIN/END macros must be defined before including this file.
 _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+
 inline file_type
-get_file_type(const ::dirent& d __attribute__((__unused__)))
+get_file_type(const std::filesystem::__gnu_posix::dirent& d [[gnu::unused]])
 {
 #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
   switch (d.d_type)
diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc
index 7e712c553c3..01c3decaba6 100644
--- a/libstdc++-v3/src/filesystem/dir.cc
+++ b/libstdc++-v3/src/filesystem/dir.cc
@@ -37,6 +37,7 @@
 #include "dir-common.h"
 
 namespace fs = std::experimental::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
 
 struct fs::_Dir : std::filesystem::_Dir_base
 {
@@ -47,7 +48,7 @@ struct fs::_Dir : std::filesystem::_Dir_base
       path = p;
   }
 
-  _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+  _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
 
   _Dir(_Dir&&) = default;
 
@@ -185,7 +186,7 @@ recursive_directory_iterator(const path& p, directory_options options,
 {
   if (ec)
     ec->clear();
-  if (DIR* dirp = ::opendir(p.c_str()))
+  if (posix::DIR* dirp = posix::opendir(p.c_str()))
     {
       auto sp = std::make_shared<_Dir_stack>();
       sp->push(_Dir{ dirp, p });
diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
index bc186836bd4..c1b817189a9 100644
--- a/libstdc++-v3/src/filesystem/ops-common.h
+++ b/libstdc++-v3/src/filesystem/ops-common.h
@@ -34,12 +34,103 @@
 #  include <sys/stat.h>
 # endif
 #endif
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <wchar.h>
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 namespace filesystem
 {
+namespace __gnu_posix
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
+  inline int open(const wchar_t* path, int flags)
+  { return ::_wopen(path, flags); }
+
+  inline int open(const wchar_t* path, int flags, int mode)
+  { return ::_wopen(path, flags, mode); }
+
+  inline int close(int fd)
+  { return ::_close(fd); }
+
+  typedef struct ::_stat stat_type;
+
+  inline int stat(const wchar_t* path, stat_type* buffer)
+  { return ::_wstat(path, buffer); }
+
+  inline lstat(const wchar_t* path, stat_type* buffer)
+  {
+    // TODO symlinks not currently supported
+    return stat(path, buffer);
+  }
+
+  using ::mode_t;
+
+  inline int chmod(const wchar_t* path, mode_t mode)
+  { return ::_wchmod(path, mode); }
+
+  inline int mkdir(const wchar_t* path, mode_t)
+  { return ::_wmkdir(path); }
+
+  inline wchar_t* getcwd(wchar_t* buf, size_t size)
+  { return ::_wgetcwd(buf, size > (size_t)INT_MAX ? INT_MAX : (int)size); }
+
+  inline int chdir(const wchar_t* path)
+  { return ::_wchdir(path); }
+
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+  using utimbuf = _utimbuf;
+
+  inline int utime(const wchar_t* path, utimbuf* times)
+  { return ::_wutime(path, times); }
+#endif
+
+  inline int rename(const wchar_t* oldname, const wchar_t* newname)
+  { return _wrename(oldname, newname); }
+
+  inline int truncate(const wchar_t* path, _off64_t length)
+  {
+    const int fd = ::_wopen(path, _O_BINARY|_O_RDWR);
+    if (fd == -1)
+      return fd;
+    const int ret = ::ftruncate64(fd, length);
+    int err;
+    ::_get_errno(&err);
+    ::_close(fd);
+    ::_set_errno(err);
+    return ret;
+  }
+  using char_type = wchar_t;
+#else // _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  using ::open;
+  using ::close;
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  typedef struct ::stat stat_type;
+  using ::stat;
+  using ::lstat;
+#endif
+  using ::mode_t;
+  using ::chmod;
+  using ::mkdir;
+  using ::getcwd;
+  using ::chdir;
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+  using ::utimbuf;
+  using ::utime;
+#endif
+  using ::rename;
+  using ::truncate;
+  using char_type = char;
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
+} // namespace __gnu_posix
+
   template<typename Bitmask>
     inline bool is_set(Bitmask obj, Bitmask bits)
     {
@@ -53,7 +144,7 @@ namespace filesystem
   }
 
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-  typedef struct ::stat stat_type;
+  using __gnu_posix::stat_type;
 
   inline std::chrono::system_clock::time_point
   file_time(const stat_type& st, std::error_code& ec) noexcept
@@ -82,11 +173,17 @@ namespace filesystem
   };
 
   bool
-  do_copy_file(const char* from, const char* to,
+  do_copy_file(const __gnu_posix::char_type* from,
+	       const __gnu_posix::char_type* to,
 	       copy_options_existing_file options,
 	       stat_type* from_st, stat_type* to_st,
 	       std::error_code& ec) noexcept;
 
+  void
+  do_space(const __gnu_posix::char_type* pathname,
+	   uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
+	   std::error_code&);
+
 #endif // _GLIBCXX_HAVE_SYS_STAT_H
 
 } // namespace filesystem
@@ -95,7 +192,7 @@ namespace filesystem
 _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
 
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-  typedef struct ::stat stat_type;
+  using std::filesystem::__gnu_posix::stat_type;
 
   inline file_type
   make_file_type(const stat_type& st) noexcept
@@ -111,8 +208,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
       return file_type::block;
     else if (S_ISFIFO(st.st_mode))
       return file_type::fifo;
+#ifdef S_ISLNK // not present in mingw
     else if (S_ISLNK(st.st_mode))
       return file_type::symlink;
+#endif
 #ifdef S_ISSOCK // not present until POSIX:2001
     else if (S_ISSOCK(st.st_mode))
       return file_type::socket;
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index 4a9e265d1d6..40cadbf6270 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -47,20 +47,17 @@
 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
 # include <utime.h> // utime
 #endif
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <windows.h>
+#endif
 
 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
   namespace experimental { namespace filesystem {
 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
 #include "ops-common.h"
 
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef utime
-# define utime _wutime
-# undef chmod
-# define chmod _wchmod
-#endif
-
 namespace fs = std::experimental::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
 
 fs::path
 fs::absolute(const path& p, const path& base)
@@ -109,7 +106,7 @@ namespace
     void operator()(void* p) const { ::free(p); }
   };
 
-  using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
+  using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
 }
 
 fs::path
@@ -122,7 +119,8 @@ fs::canonical(const path& p, const path& base, error_code& ec)
   char_ptr buf{ nullptr };
 # if _XOPEN_VERSION < 700
   // Not safe to call realpath(path, NULL)
-  buf.reset( (char*)::malloc(PATH_MAX) );
+  using char_type = fs::path::value_type;
+  buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
 # endif
   if (char* rp = ::realpath(pa.c_str(), buf.get()))
     {
@@ -241,12 +239,13 @@ namespace
   using std::filesystem::is_set;
 
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-  typedef struct ::stat stat_type;
+  using posix::stat_type;
 
   using std::filesystem::is_not_found_errno;
   using std::filesystem::file_time;
   using std::filesystem::do_copy_file;
 #endif // _GLIBCXX_HAVE_SYS_STAT_H
+
 } // namespace
 
 void
@@ -263,15 +262,15 @@ fs::copy(const path& from, const path& to, copy_options options,
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 2681. filesystem::copy() cannot copy symlinks
   if (use_lstat || copy_symlinks
-      ? ::lstat(from.c_str(), &from_st)
-      : ::stat(from.c_str(), &from_st))
+      ? posix::lstat(from.c_str(), &from_st)
+      : posix::stat(from.c_str(), &from_st))
     {
       ec.assign(errno, std::generic_category());
       return;
     }
   if (use_lstat
-      ? ::lstat(to.c_str(), &to_st)
-      : ::stat(to.c_str(), &to_st))
+      ? posix::lstat(to.c_str(), &to_st)
+      : posix::stat(to.c_str(), &to_st))
     {
       if (!is_not_found_errno(errno))
 	{
@@ -459,8 +458,8 @@ namespace
   {
     bool created = false;
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-    ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
-    if (::mkdir(p.c_str(), mode))
+    posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+    if (posix::mkdir(p.c_str(), mode))
       {
 	const int err = errno;
 	if (err != EEXIST || !is_directory(p, ec))
@@ -513,7 +512,7 @@ fs::create_directory(const path& p, const path& attributes,
 {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
   stat_type st;
-  if (::stat(attributes.c_str(), &st))
+  if (posix::stat(attributes.c_str(), &st))
     {
       ec.assign(errno, std::generic_category());
       return false;
@@ -562,11 +561,16 @@ void
 fs::create_hard_link(const path& to, const path& new_hard_link,
 		     error_code& ec) noexcept
 {
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_LINK
   if (::link(to.c_str(), new_hard_link.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
+#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
+    ec.clear();
+  else
+    ec.assign((int)GetLastError(), generic_category());
 #else
   ec = std::make_error_code(std::errc::not_supported);
 #endif
@@ -586,7 +590,7 @@ void
 fs::create_symlink(const path& to, const path& new_symlink,
 		   error_code& ec) noexcept
 {
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_SYMLINK
   if (::symlink(to.c_str(), new_symlink.c_str()))
     ec.assign(errno, std::generic_category());
   else
@@ -596,7 +600,6 @@ fs::create_symlink(const path& to, const path& new_symlink,
 #endif
 }
 
-
 fs::path
 fs::current_path()
 {
@@ -612,8 +615,8 @@ fs::current_path(error_code& ec)
 {
   path p;
 #ifdef _GLIBCXX_HAVE_UNISTD_H
-#ifdef __GLIBC__
-  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
+#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
     {
       p.assign(cwd.get());
       ec.clear();
@@ -621,6 +624,7 @@ fs::current_path(error_code& ec)
   else
     ec.assign(errno, std::generic_category());
 #else
+#ifdef _PC_PATH_MAX
   long path_max = pathconf(".", _PC_PATH_MAX);
   size_t size;
   if (path_max == -1)
@@ -629,9 +633,15 @@ fs::current_path(error_code& ec)
       size = 10240;
   else
       size = path_max;
+#elif defined(PATH_MAX)
+  size_t size = PATH_MAX;
+#else
+  size_t size = 1024;
+#endif
   for (char_ptr buf; p.empty(); size *= 2)
     {
-      buf.reset((char*)malloc(size));
+      using char_type = fs::path::value_type;
+      buf.reset((char_type*)malloc(size * sizeof(char_type)));
       if (buf)
 	{
 	  if (getcwd(buf.get(), size))
@@ -671,7 +681,7 @@ void
 fs::current_path(const path& p, error_code& ec) noexcept
 {
 #ifdef _GLIBCXX_HAVE_UNISTD_H
-  if (::chdir(p.c_str()))
+  if (posix::chdir(p.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -698,14 +708,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
   int err = 0;
   file_status s1, s2;
   stat_type st1, st2;
-  if (::stat(p1.c_str(), &st1) == 0)
+  if (posix::stat(p1.c_str(), &st1) == 0)
     s1 = make_file_status(st1);
   else if (is_not_found_errno(errno))
     s1.type(file_type::not_found);
   else
     err = errno;
 
-  if (::stat(p2.c_str(), &st2) == 0)
+  if (posix::stat(p2.c_str(), &st2) == 0)
     s2 = make_file_status(st2);
   else if (is_not_found_errno(errno))
     s2.type(file_type::not_found);
@@ -755,7 +765,7 @@ namespace
     {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
       stat_type st;
-      if (::stat(p.c_str(), &st))
+      if (posix::stat(p.c_str(), &st))
 	{
 	  ec.assign(errno, std::generic_category());
 	  return deflt;
@@ -805,7 +815,7 @@ fs::hard_link_count(const path& p)
 std::uintmax_t
 fs::hard_link_count(const path& p, error_code& ec) noexcept
 {
-  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
+  return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
 		 static_cast<uintmax_t>(-1));
 }
 
@@ -881,11 +891,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)),
   else
     ec.clear();
 #elif _GLIBCXX_HAVE_UTIME_H
-  ::utimbuf times;
+  posix::utimbuf times;
   times.modtime = s.count();
   times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
 			 times.modtime);
-  if (::utime(p.c_str(), &times))
+  if (posix::utime(p.c_str(), &times))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -938,7 +948,7 @@ fs::permissions(const path& p, perms prms, error_code& ec) noexcept
 #else
   if (nofollow && is_symlink(st))
     ec = std::make_error_code(std::errc::operation_not_supported);
-  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+  else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
     err = errno;
 #endif
 
@@ -958,10 +968,10 @@ fs::read_symlink(const path& p)
   return tgt;
 }
 
-fs::path fs::read_symlink(const path& p, error_code& ec)
+fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
 {
   path result;
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
   stat_type st;
   if (::lstat(p.c_str(), &st))
     {
@@ -1015,6 +1025,19 @@ fs::remove(const path& p)
 bool
 fs::remove(const path& p, error_code& ec) noexcept
 {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (exists(symlink_status(p, ec)))
+    {
+      if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
+	  || DeleteFileW(p.c_str()))
+	{
+	  ec.clear();
+	  return true;
+	}
+      else if (!ec)
+	ec.assign((int)GetLastError(), generic_category());
+    }
+#else
   if (::remove(p.c_str()) == 0)
     {
       ec.clear();
@@ -1024,6 +1047,7 @@ fs::remove(const path& p, error_code& ec) noexcept
     ec.clear();
   else
     ec.assign(errno, std::generic_category());
+#endif
   return false;
 }
 
@@ -1077,7 +1101,7 @@ fs::rename(const path& from, const path& to)
 void
 fs::rename(const path& from, const path& to, error_code& ec) noexcept
 {
-  if (::rename(from.c_str(), to.c_str()))
+  if (posix::rename(from.c_str(), to.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -1098,7 +1122,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
 #ifdef _GLIBCXX_HAVE_UNISTD_H
   if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
     ec.assign(EINVAL, std::generic_category());
-  else if (::truncate(p.c_str(), size))
+  else if (posix::truncate(p.c_str(), size))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -1126,23 +1150,14 @@ fs::space(const path& p, error_code& ec) noexcept
     static_cast<uintmax_t>(-1),
     static_cast<uintmax_t>(-1)
   };
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
-  struct ::statvfs f;
-  if (::statvfs(p.c_str(), &f))
-      ec.assign(errno, std::generic_category());
-  else
-    {
-      uintmax_t fragment_size = f.f_frsize;
-      info = space_info{
-	f.f_blocks * fragment_size,
-	f.f_bfree * fragment_size,
-	f.f_bavail * fragment_size
-      };
-      ec.clear();
-    }
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  path dir = absolute(p);
+  dir.remove_filename();
+  auto str = dir.c_str();
 #else
-  ec = std::make_error_code(std::errc::not_supported);
+  auto str = p.c_str();
 #endif
+  std::filesystem::do_space(str, info.capacity, info.free, info.available, ec);
   return info;
 }
 
@@ -1152,7 +1167,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept
 {
   file_status status;
   stat_type st;
-  if (::stat(p.c_str(), &st))
+  if (posix::stat(p.c_str(), &st))
     {
       int err = errno;
       ec.assign(err, std::generic_category());
@@ -1176,7 +1191,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
 {
   file_status status;
   stat_type st;
-  if (::lstat(p.c_str(), &st))
+  if (posix::lstat(p.c_str(), &st))
     {
       int err = errno;
       ec.assign(err, std::generic_category());
@@ -1251,27 +1266,38 @@ fs::path fs::temp_directory_path()
 
 fs::path fs::temp_directory_path(error_code& ec)
 {
+  path p;
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  ec = std::make_error_code(std::errc::not_supported);
-  return {}; // TODO
+  unsigned len = 1024;
+  std::wstring buf;
+  do
+    {
+      buf.resize(len);
+      len = GetTempPathW(buf.size(), buf.data());
+    } while (len > buf.size());
+
+  if (len == 0)
+    {
+      ec.assign((int)GetLastError(), std::system_category());
+      return p;
+    }
+  buf.resize(len);
+  p = std::move(buf);
 #else
   const char* tmpdir = nullptr;
   const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
   for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
     tmpdir = ::getenv(*e);
-  path p = tmpdir ? tmpdir : "/tmp";
+  p = tmpdir ? tmpdir : "/tmp";
   auto st = status(p, ec);
-  if (!ec)
+  if (ec)
+    p.clear();
+  else if (!is_directory(st))
     {
-      if (is_directory(st))
-	{
-	  ec.clear();
-	  return p;
-	}
-      else
-	ec = std::make_error_code(std::errc::not_a_directory);
+      p.clear();
+      ec = std::make_error_code(std::errc::not_a_directory);
     }
-  return {};
 #endif
+  return p;
 }
 
diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc
index 899d94e0067..fb70d30fdca 100644
--- a/libstdc++-v3/src/filesystem/path.cc
+++ b/libstdc++-v3/src/filesystem/path.cc
@@ -61,6 +61,12 @@ path::replace_filename(const path& replacement)
   return *this;
 }
 
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+const fs::path::value_type dot = L'.';
+#else
+const fs::path::value_type dot = '.';
+#endif
+
 path&
 path::replace_extension(const path& replacement)
 {
@@ -78,8 +84,8 @@ path::replace_extension(const path& replacement)
 	  _M_pathname.erase(back._M_pos + ext.second);
 	}
     }
-  if (!replacement.empty() && replacement.native()[0] != '.')
-    _M_pathname += '.';
+  if (!replacement.empty() && replacement.native()[0] != dot)
+    _M_pathname += dot;
   _M_pathname += replacement.native();
   _M_split_cmpts();
   return *this;
@@ -297,7 +303,7 @@ path::has_filename() const
 std::pair<const path::string_type*, std::size_t>
 path::_M_find_extension() const
 {
-  const std::string* s = nullptr;
+  const string_type* s = nullptr;
 
   if (_M_type != _Type::_Multi)
     s = &_M_pathname;
@@ -312,14 +318,14 @@ path::_M_find_extension() const
     {
       if (auto sz = s->size())
 	{
-	  if (sz <= 2 && (*s)[0] == '.')
+	  if (sz <= 2 && (*s)[0] == dot)
 	    {
-	      if (sz == 1 || (*s)[1] == '.')  // filename is "." or ".."
+	      if (sz == 1 || (*s)[1] == dot)  // filename is "." or ".."
 		return { s, string_type::npos };
 	      else
 		return { s, 0 };  // filename is like ".?"
 	    }
-	  return { s, s->rfind('.') };
+	  return { s, s->rfind(dot) };
 	}
     }
   return {};
@@ -405,7 +411,7 @@ path::_M_split_cmpts()
 	{
 	  const auto& last = _M_cmpts.back();
 	  pos = last._M_pos + last._M_pathname.size();
-	  _M_cmpts.emplace_back(string_type(1, '.'), _Type::_Filename, pos);
+	  _M_cmpts.emplace_back(string_type(1, dot), _Type::_Filename, pos);
 	}
     }
 
@@ -495,8 +501,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   std::string filesystem_error::_M_gen_what()
   {
     using std::filesystem::fs_err_concat;
-    return fs_err_concat(system_error::what(), _M_path1.native(),
-			 _M_path2.native());
+    return fs_err_concat(system_error::what(), _M_path1.u8string(),
+			 _M_path2.u8string());
   }
 
 _GLIBCXX_END_NAMESPACE_CXX11
diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc
index 98eb22ab920..4c9a287ad80 100644
--- a/libstdc++-v3/src/filesystem/std-dir.cc
+++ b/libstdc++-v3/src/filesystem/std-dir.cc
@@ -37,6 +37,7 @@
 #include "dir-common.h"
 
 namespace fs = std::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
 
 struct fs::_Dir : _Dir_base
 {
@@ -47,7 +48,7 @@ struct fs::_Dir : _Dir_base
       path = p;
   }
 
-  _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+  _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
 
   _Dir(_Dir&&) = default;
 
@@ -180,7 +181,7 @@ recursive_directory_iterator(const path& p, directory_options options,
                              error_code* ecptr)
 : _M_options(options), _M_pending(true)
 {
-  if (DIR* dirp = ::opendir(p.c_str()))
+  if (posix::DIR* dirp = posix::opendir(p.c_str()))
     {
       if (ecptr)
 	ecptr->clear();
diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc
index 00e4f987fc3..e266fa6d3f8 100644
--- a/libstdc++-v3/src/filesystem/std-ops.cc
+++ b/libstdc++-v3/src/filesystem/std-ops.cc
@@ -25,6 +25,7 @@
 #ifndef _GLIBCXX_USE_CXX11_ABI
 # define _GLIBCXX_USE_CXX11_ABI 1
 # define NEED_DO_COPY_FILE
+# define NEED_DO_SPACE
 #endif
 
 #include <filesystem>
@@ -52,19 +53,16 @@
 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
 # include <utime.h> // utime
 #endif
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <windows.h>
+#endif
 
 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
 #include "ops-common.h"
 
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef utime
-# define utime _wutime
-# undef chmod
-# define chmod _wchmod
-#endif
-
 namespace fs = std::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
 
 fs::path
 fs::absolute(const path& p)
@@ -74,7 +72,7 @@ fs::absolute(const path& p)
   path ret = absolute(p, ec);
   if (ec)
     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
-	std::make_error_code(errc::not_supported)));
+					     ec));
   return ret;
 #else
   return current_path() / p;
@@ -91,7 +89,24 @@ fs::absolute(const path& p, error_code& ec)
       return ret;
     }
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  ec = std::make_error_code(errc::not_supported);
+  const wstring& s = p.native();
+  uint32_t len = 1024;
+  wstring buf;
+  do
+    {
+      buf.resize(len);
+      len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr);
+    }
+  while (len > buf.size());
+
+  if (len == 0)
+    ec.assign((int)GetLastError(), std::system_category());
+  else
+    {
+      ec.clear();
+      buf.resize(len);
+      ret = std::move(buf);
+    }
 #else
   ec.clear();
   ret = current_path();
@@ -125,7 +140,7 @@ namespace
     void operator()(void* p) const { ::free(p); }
   };
 
-  using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
+  using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
 }
 
 fs::path
@@ -140,7 +155,8 @@ fs::canonical(const path& p, error_code& ec)
   char_ptr buf{ nullptr };
 # if _XOPEN_VERSION < 700
   // Not safe to call realpath(path, NULL)
-  buf.reset( (char*)::malloc(PATH_MAX) );
+  using char_type = fs::path::value_type;
+  buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
 # endif
   if (char* rp = ::realpath(pa.c_str(), buf.get()))
     {
@@ -261,7 +277,7 @@ namespace std::filesystem
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
 #ifdef NEED_DO_COPY_FILE
 bool
-fs::do_copy_file(const char* from, const char* to,
+fs::do_copy_file(const path::value_type* from, const path::value_type* to,
 		 copy_options_existing_file options,
 		 stat_type* from_st, stat_type* to_st,
 		 std::error_code& ec) noexcept
@@ -271,7 +287,7 @@ fs::do_copy_file(const char* from, const char* to,
 
   if (to_st == nullptr)
     {
-      if (::stat(to, &st1))
+      if (posix::stat(to, &st1))
 	{
 	  const int err = errno;
 	  if (!is_not_found_errno(err))
@@ -293,7 +309,7 @@ fs::do_copy_file(const char* from, const char* to,
 
   if (from_st == nullptr)
     {
-      if (::stat(from, &st2))
+      if (posix::stat(from, &st2))
 	{
 	  ec.assign(errno, std::generic_category());
 	  return false;
@@ -351,12 +367,12 @@ fs::do_copy_file(const char* from, const char* to,
     }
 
   struct CloseFD {
-    ~CloseFD() { if (fd != -1) ::close(fd); }
-    bool close() { return ::close(std::exchange(fd, -1)) == 0; }
+    ~CloseFD() { if (fd != -1) posix::close(fd); }
+    bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
     int fd;
   };
 
-  CloseFD in = { ::open(from, O_RDONLY) };
+  CloseFD in = { posix::open(from, O_RDONLY) };
   if (in.fd == -1)
     {
       ec.assign(errno, std::generic_category());
@@ -367,7 +383,7 @@ fs::do_copy_file(const char* from, const char* to,
     oflag |= O_TRUNC;
   else
     oflag |= O_EXCL;
-  CloseFD out = { ::open(to, oflag, S_IWUSR) };
+  CloseFD out = { posix::open(to, oflag, S_IWUSR) };
   if (out.fd == -1)
     {
       if (errno == EEXIST && options.skip)
@@ -377,12 +393,12 @@ fs::do_copy_file(const char* from, const char* to,
       return false;
     }
 
-#ifdef _GLIBCXX_USE_FCHMOD
+#if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
   if (::fchmod(out.fd, from_st->st_mode))
-#elif defined _GLIBCXX_USE_FCHMODAT
+#elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
   if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
 #else
-  if (::chmod(to, from_st->st_mode))
+  if (posix::chmod(to, from_st->st_mode))
 #endif
     {
       ec.assign(errno, std::generic_category());
@@ -390,7 +406,7 @@ fs::do_copy_file(const char* from, const char* to,
     }
 
   size_t count = from_st->st_size;
-#ifdef _GLIBCXX_USE_SENDFILE
+#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
   off_t offset = 0;
   ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
   if (n < 0 && errno != ENOSYS && errno != EINVAL)
@@ -469,15 +485,15 @@ fs::copy(const path& from, const path& to, copy_options options,
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 2681. filesystem::copy() cannot copy symlinks
   if (use_lstat || copy_symlinks
-      ? ::lstat(from.c_str(), &from_st)
-      : ::stat(from.c_str(), &from_st))
+      ? posix::lstat(from.c_str(), &from_st)
+      : posix::stat(from.c_str(), &from_st))
     {
       ec.assign(errno, std::generic_category());
       return;
     }
   if (use_lstat
-      ? ::lstat(to.c_str(), &to_st)
-      : ::stat(to.c_str(), &to_st))
+      ? posix::lstat(to.c_str(), &to_st)
+      : posix::stat(to.c_str(), &to_st))
     {
       if (!is_not_found_errno(errno))
 	{
@@ -671,8 +687,9 @@ namespace
   {
     bool created = false;
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-    ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
-    if (::mkdir(p.c_str(), mode))
+    posix::mode_t mode
+      = static_cast<std::underlying_type_t<fs::perms>>(perm);
+    if (posix::mkdir(p.c_str(), mode))
       {
 	const int err = errno;
 	if (err != EEXIST || !is_directory(p, ec))
@@ -725,7 +742,7 @@ fs::create_directory(const path& p, const path& attributes,
 {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
   stat_type st;
-  if (::stat(attributes.c_str(), &st))
+  if (posix::stat(attributes.c_str(), &st))
     {
       ec.assign(errno, std::generic_category());
       return false;
@@ -767,18 +784,23 @@ fs::create_hard_link(const path& to, const path& new_hard_link)
   create_hard_link(to, new_hard_link, ec);
   if (ec)
     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
-	  to, new_hard_link, ec));
+					     to, new_hard_link, ec));
 }
 
 void
 fs::create_hard_link(const path& to, const path& new_hard_link,
 		     error_code& ec) noexcept
 {
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_LINK
   if (::link(to.c_str(), new_hard_link.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
+#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
+    ec.clear();
+  else
+    ec.assign((int)GetLastError(), generic_category());
 #else
   ec = std::make_error_code(std::errc::not_supported);
 #endif
@@ -798,7 +820,7 @@ void
 fs::create_symlink(const path& to, const path& new_symlink,
 		   error_code& ec) noexcept
 {
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_SYMLINK
   if (::symlink(to.c_str(), new_symlink.c_str()))
     ec.assign(errno, std::generic_category());
   else
@@ -824,8 +846,8 @@ fs::current_path(error_code& ec)
 {
   path p;
 #ifdef _GLIBCXX_HAVE_UNISTD_H
-#ifdef __GLIBC__
-  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
+#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
     {
       p.assign(cwd.get());
       ec.clear();
@@ -833,6 +855,7 @@ fs::current_path(error_code& ec)
   else
     ec.assign(errno, std::generic_category());
 #else
+#ifdef _PC_PATH_MAX
   long path_max = pathconf(".", _PC_PATH_MAX);
   size_t size;
   if (path_max == -1)
@@ -841,9 +864,15 @@ fs::current_path(error_code& ec)
       size = 10240;
   else
       size = path_max;
+#elif defined(PATH_MAX)
+  size_t size = PATH_MAX;
+#else
+  size_t size = 1024;
+#endif
   for (char_ptr buf; p.empty(); size *= 2)
     {
-      buf.reset((char*)malloc(size));
+      using char_type = fs::path::value_type;
+      buf.reset((char_type*)malloc(size * sizeof(char_type)));
       if (buf)
 	{
 	  if (getcwd(buf.get(), size))
@@ -883,7 +912,7 @@ void
 fs::current_path(const path& p, error_code& ec) noexcept
 {
 #ifdef _GLIBCXX_HAVE_UNISTD_H
-  if (::chdir(p.c_str()))
+  if (posix::chdir(p.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -910,14 +939,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
   int err = 0;
   file_status s1, s2;
   stat_type st1, st2;
-  if (::stat(p1.c_str(), &st1) == 0)
+  if (posix::stat(p1.c_str(), &st1) == 0)
     s1 = make_file_status(st1);
   else if (is_not_found_errno(errno))
     s1.type(file_type::not_found);
   else
     err = errno;
 
-  if (::stat(p2.c_str(), &st2) == 0)
+  if (posix::stat(p2.c_str(), &st2) == 0)
     s2 = make_file_status(st2);
   else if (is_not_found_errno(errno))
     s2.type(file_type::not_found);
@@ -966,8 +995,8 @@ namespace
     do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
     {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-      fs::stat_type st;
-      if (::stat(p.c_str(), &st))
+      posix::stat_type st;
+      if (posix::stat(p.c_str(), &st))
 	{
 	  ec.assign(errno, std::generic_category());
 	  return deflt;
@@ -1017,7 +1046,7 @@ fs::hard_link_count(const path& p)
 std::uintmax_t
 fs::hard_link_count(const path& p, error_code& ec) noexcept
 {
-  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
+  return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
 		 static_cast<uintmax_t>(-1));
 }
 
@@ -1093,11 +1122,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)),
   else
     ec.clear();
 #elif _GLIBCXX_HAVE_UTIME_H
-  ::utimbuf times;
+  posix::utimbuf times;
   times.modtime = s.count();
   times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
 			 times.modtime);
-  if (::utime(p.c_str(), &times))
+  if (posix::utime(p.c_str(), &times))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -1152,7 +1181,7 @@ fs::permissions(const path& p, perms prms, perm_options opts,
 #else
   if (nofollow && is_symlink(st))
     ec = std::make_error_code(std::errc::operation_not_supported);
-  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+  else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
     err = errno;
 #endif
 
@@ -1192,10 +1221,10 @@ fs::read_symlink(const path& p)
   return tgt;
 }
 
-fs::path fs::read_symlink(const path& p, error_code& ec)
+fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
 {
   path result;
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
   stat_type st;
   if (::lstat(p.c_str(), &st))
     {
@@ -1268,6 +1297,19 @@ fs::remove(const path& p)
 bool
 fs::remove(const path& p, error_code& ec) noexcept
 {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (exists(symlink_status(p, ec)))
+    {
+      if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
+	  || DeleteFileW(p.c_str()))
+	{
+	  ec.clear();
+	  return true;
+	}
+      else if (!ec)
+	ec.assign((int)GetLastError(), generic_category());
+    }
+#else
   if (::remove(p.c_str()) == 0)
     {
       ec.clear();
@@ -1277,6 +1319,7 @@ fs::remove(const path& p, error_code& ec) noexcept
     ec.clear();
   else
     ec.assign(errno, std::generic_category());
+#endif
   return false;
 }
 
@@ -1330,7 +1373,7 @@ fs::rename(const path& from, const path& to)
 void
 fs::rename(const path& from, const path& to, error_code& ec) noexcept
 {
-  if (::rename(from.c_str(), to.c_str()))
+  if (posix::rename(from.c_str(), to.c_str()))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -1351,7 +1394,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
 #ifdef _GLIBCXX_HAVE_UNISTD_H
   if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
     ec.assign(EINVAL, std::generic_category());
-  else if (::truncate(p.c_str(), size))
+  else if (posix::truncate(p.c_str(), size))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
@@ -1371,6 +1414,51 @@ fs::space(const path& p)
   return s;
 }
 
+#ifdef NEED_DO_SPACE
+void
+fs::do_space(const __gnu_posix::char_type* pathname,
+	 uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
+	 std::error_code& ec)
+{
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+  struct ::statvfs f;
+  if (::statvfs(pathname, &f))
+      ec.assign(errno, std::generic_category());
+  else
+    {
+      if (f.f_frsize != (unsigned long)-1)
+	{
+	  const uintmax_t fragment_size = f.f_frsize;
+	  const fsblkcnt_t unknown = -1;
+	  if (f.f_blocks != unknown)
+	    capacity = f.f_blocks * fragment_size;
+	  if (f.f_bfree != unknown)
+	    free = f.f_bfree * fragment_size;
+	  if (f.f_bavail != unknown)
+	    available = f.f_bavail * fragment_size;
+	}
+      ec.clear();
+    }
+#elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
+  if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
+    {
+      if (bytes_total.QuadPart != 0)
+	capacity = bytes_total.QuadPart;
+      if (bytes_free.QuadPart != 0)
+	free = bytes_free.QuadPart;
+      if (bytes_avail.QuadPart != 0)
+	available = bytes_avail.QuadPart;
+      ec.clear();
+    }
+  else
+    ec.assign((int)GetLastError(), std::system_category());
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+#endif // NEED_DO_SPACE
+
 fs::space_info
 fs::space(const path& p, error_code& ec) noexcept
 {
@@ -1379,23 +1467,14 @@ fs::space(const path& p, error_code& ec) noexcept
     static_cast<uintmax_t>(-1),
     static_cast<uintmax_t>(-1)
   };
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
-  struct ::statvfs f;
-  if (::statvfs(p.c_str(), &f))
-      ec.assign(errno, std::generic_category());
-  else
-    {
-      uintmax_t fragment_size = f.f_frsize;
-      info = space_info{
-	f.f_blocks * fragment_size,
-	f.f_bfree * fragment_size,
-	f.f_bavail * fragment_size
-      };
-      ec.clear();
-    }
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  path dir = absolute(p);
+  dir.remove_filename();
+  auto str = dir.c_str();
 #else
-  ec = std::make_error_code(std::errc::not_supported);
+  auto str = p.c_str();
 #endif
+  do_space(str, info.capacity, info.free, info.available, ec);
   return info;
 }
 
@@ -1405,7 +1484,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept
 {
   file_status status;
   stat_type st;
-  if (::stat(p.c_str(), &st))
+  if (posix::stat(p.c_str(), &st))
     {
       int err = errno;
       ec.assign(err, std::generic_category());
@@ -1429,7 +1508,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
 {
   file_status status;
   stat_type st;
-  if (::lstat(p.c_str(), &st))
+  if (posix::lstat(p.c_str(), &st))
     {
       int err = errno;
       ec.assign(err, std::generic_category());
@@ -1476,28 +1555,39 @@ fs::path fs::temp_directory_path()
 
 fs::path fs::temp_directory_path(error_code& ec)
 {
+  path p;
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  ec = std::make_error_code(std::errc::not_supported);
-  return {}; // TODO
+  unsigned len = 1024;
+  std::wstring buf;
+  do
+    {
+      buf.resize(len);
+      len = GetTempPathW(buf.size(), buf.data());
+    } while (len > buf.size());
+
+  if (len == 0)
+    {
+      ec.assign((int)GetLastError(), std::system_category());
+      return p;
+    }
+  buf.resize(len);
+  p = std::move(buf);
 #else
   const char* tmpdir = nullptr;
   const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
   for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
     tmpdir = ::getenv(*e);
-  path p = tmpdir ? tmpdir : "/tmp";
-  auto st = status(p, ec);
-  if (!ec)
-    {
-      if (is_directory(st))
-	{
-	  ec.clear();
-	  return p;
-	}
-      else
-	ec = std::make_error_code(std::errc::not_a_directory);
-    }
-  return {};
+  p = tmpdir ? tmpdir : "/tmp";
 #endif
+  auto st = status(p, ec);
+  if (ec)
+    p.clear();
+  else if (!is_directory(st))
+    {
+      p.clear();
+      ec = std::make_error_code(std::errc::not_a_directory);
+    }
+  return p;
 }
 
 fs::path
diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
index 755cb7c883a..f6c0b8bb0f6 100644
--- a/libstdc++-v3/src/filesystem/std-path.cc
+++ b/libstdc++-v3/src/filesystem/std-path.cc
@@ -38,6 +38,66 @@ fs::filesystem_error::~filesystem_error() = default;
 
 constexpr path::value_type path::preferred_separator;
 
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+path&
+path::operator/=(const path& __p)
+{
+  if (__p.is_absolute()
+      || (__p.has_root_name() && __p.root_name() != root_name()))
+    return operator=(__p);
+
+  basic_string_view<value_type> __lhs = _M_pathname;
+  bool __add_sep = false;
+
+  if (__p.has_root_directory())
+    {
+      // Remove any root directory and relative path
+      if (_M_type != _Type::_Root_name)
+	{
+	  if (!_M_cmpts.empty()
+	      && _M_cmpts.front()._M_type == _Type::_Root_name)
+	    __lhs = _M_cmpts.front()._M_pathname;
+	  else
+	    __lhs = {};
+	}
+    }
+  else if (has_filename() || (!has_root_directory() && is_absolute()))
+    __add_sep = true;
+
+  basic_string_view<value_type> __rhs = __p._M_pathname;
+  // Omit any root-name from the generic format pathname:
+  if (__p._M_type == _Type::_Root_name)
+    __rhs = {};
+  else if (!__p._M_cmpts.empty()
+      && __p._M_cmpts.front()._M_type == _Type::_Root_name)
+    __rhs.remove_prefix(__p._M_cmpts.front()._M_pathname.size());
+
+  const size_t __len = __lhs.size() + (int)__add_sep + __rhs.size();
+  const size_t __maxcmpts = _M_cmpts.size() + __p._M_cmpts.size();
+  if (_M_pathname.capacity() < __len || _M_cmpts.capacity() < __maxcmpts)
+    {
+      // Construct new path and swap (strong exception-safety guarantee).
+      string_type __tmp;
+      __tmp.reserve(__len);
+      __tmp = __lhs;
+      if (__add_sep)
+	__tmp += preferred_separator;
+      __tmp += __rhs;
+      path __newp = std::move(__tmp);
+      swap(__newp);
+    }
+  else
+    {
+      _M_pathname = __lhs;
+      if (__add_sep)
+	_M_pathname += preferred_separator;
+      _M_pathname += __rhs;
+      _M_split_cmpts();
+    }
+  return *this;
+}
+#endif
+
 path&
 path::remove_filename()
 {
@@ -74,6 +134,12 @@ path::replace_filename(const path& replacement)
   return *this;
 }
 
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+const fs::path::value_type dot = L'.';
+#else
+const fs::path::value_type dot = '.';
+#endif
+
 path&
 path::replace_extension(const path& replacement)
 {
@@ -94,8 +160,8 @@ path::replace_extension(const path& replacement)
     }
    // If replacement is not empty and does not begin with a dot character,
    // a dot character is appended
-  if (!replacement.empty() && replacement.native()[0] != '.')
-    _M_pathname += '.';
+  if (!replacement.empty() && replacement.native()[0] != dot)
+    _M_pathname += dot;
   operator+=(replacement);
   return *this;
 }
@@ -332,11 +398,7 @@ path::has_filename() const
 
 namespace
 {
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  inline bool is_dot(wchar_t c) { return c == L'.'; }
-#else
-  inline bool is_dot(char c) { return c == '.'; }
-#endif
+  inline bool is_dot(fs::path::value_type c) { return c == dot; }
 
   inline bool is_dot(const fs::path& path)
   {
@@ -376,7 +438,7 @@ path::lexically_normal() const
     {
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
       // Replace each slash character in the root-name
-      if (p.is_root_name())
+      if (p._M_type == _Type::_Root_name)
 	{
 	  string_type s = p.native();
 	  std::replace(s.begin(), s.end(), L'/', L'\\');
@@ -485,7 +547,7 @@ path::lexically_proximate(const path& base) const
 std::pair<const path::string_type*, std::size_t>
 path::_M_find_extension() const
 {
-  const std::string* s = nullptr;
+  const string_type* s = nullptr;
 
   if (_M_type == _Type::_Filename)
     s = &_M_pathname;
@@ -500,9 +562,9 @@ path::_M_find_extension() const
     {
       if (auto sz = s->size())
 	{
-	  if (sz <= 2 && (*s)[0] == '.')
+	  if (sz <= 2 && (*s)[0] == dot)
 	    return { s, string_type::npos };
-	  const auto pos = s->rfind('.');
+	  const auto pos = s->rfind(dot);
 	  return { s, pos ? pos : string_type::npos };
 	}
     }
@@ -703,8 +765,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
   std::string filesystem_error::_M_gen_what()
   {
-    return fs_err_concat(system_error::what(), _M_path1.native(),
-			 _M_path2.native());
+    return fs_err_concat(system_error::what(), _M_path1.u8string(),
+			 _M_path2.u8string());
   }
 
 _GLIBCXX_END_NAMESPACE_CXX11
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
index 428a799013f..b2445f72b5c 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
@@ -47,16 +47,17 @@ test01()
 
   // Test non-empty directory.
   ec = bad_ec;
-  create_directory_symlink(p, p / "l", ec);
+  create_directory(p / "x", ec);
   VERIFY( !ec );
   ec = bad_ec;
   iter = fs::directory_iterator(p, ec);
   VERIFY( !ec );
   VERIFY( iter != fs::directory_iterator() );
-  VERIFY( iter->path() == p/"l" );
+  VERIFY( iter->path() == p/"x" );
   ++iter;
   VERIFY( iter == end(iter) );
 
+#if !(defined(__MINGW32__) || defined(__MINGW64__))
   // Test inaccessible directory.
   ec = bad_ec;
   permissions(p, fs::perms::none, ec);
@@ -71,6 +72,7 @@ test01()
   iter = fs::directory_iterator(p, opts, ec);
   VERIFY( !ec );
   VERIFY( iter == end(iter) );
+#endif
 
   permissions(p, fs::perms::owner_all, ec);
   remove_all(p, ec);
@@ -84,7 +86,7 @@ test02()
   const auto p = __gnu_test::nonexistent_path();
   ec = bad_ec;
   create_directory(p, fs::current_path(), ec);
-  create_directory_symlink(p, p / "l", ec);
+  create_directory(p / "x", ec);
   VERIFY( !ec );
 
   // Test post-increment (libstdc++/71005)
@@ -95,7 +97,7 @@ test02()
   const auto entry1 = *iter;
   const auto entry2 = *iter++;
   VERIFY( entry1 == entry2 );
-  VERIFY( entry1.path() == p/"l" );
+  VERIFY( entry1.path() == p/"x" );
   VERIFY( iter == end(iter) );
 
   remove_all(p, ec);
@@ -130,7 +132,7 @@ test05()
 {
   auto p = __gnu_test::nonexistent_path();
   create_directory(p);
-  create_directory_symlink(p, p / "l");
+  create_directory(p / "x");
   fs::directory_iterator it(p), endit;
   VERIFY( begin(it) == it );
   static_assert( noexcept(begin(it)), "begin is noexcept" );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
index c391cd91113..8a5b8c3a0e2 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
@@ -60,6 +60,7 @@ test01()
   ++iter;
   VERIFY( iter == end(iter) );
 
+#if ! (defined (__MINGW32__) || defined(__MINGW64__))
   // Test inaccessible directory.
   ec = bad_ec;
   permissions(p, fs::perms::none, ec);
@@ -106,6 +107,7 @@ test01()
   iter.increment(ec);  // should fail to recurse into p/d1/d2, so skip it
   VERIFY( !ec );
   VERIFY( iter == end(iter) );
+#endif
 
   permissions(p/"d1/d2", fs::perms::owner_all, ec);
   remove_all(p, ec);
@@ -171,7 +173,7 @@ test05()
 {
   auto p = __gnu_test::nonexistent_path();
   create_directory(p);
-  create_directory_symlink(p, p / "l");
+  create_directory(p / "x");
   fs::recursive_directory_iterator it(p), endit;
   VERIFY( begin(it) == it );
   static_assert( noexcept(begin(it)), "begin is noexcept" );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
index 413a86758f0..596ddd33f9d 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
@@ -41,6 +41,22 @@ test01()
 void
 test02()
 {
+  std::error_code ec = make_error_code(std::errc::invalid_argument);
+  path root = __gnu_test::root_path();
+  VERIFY( absolute(root) == root );
+  VERIFY( absolute(root, ec) == root && !ec );
+  VERIFY( absolute(path{}, ec).empty() && ec );
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  path p1("/");
+  VERIFY( absolute(p1) != p1 );
+  path p2("/foo");
+  VERIFY( absolute(p2) != p2 );
+  path p3("foo");
+  VERIFY( absolute(p3) != p3 );
+  path p4("C:\\");
+  VERIFY( absolute(p4) == p4 );
+#else
   path p1("/");
   VERIFY( absolute(p1) == p1 );
   path p2("/foo");
@@ -48,6 +64,7 @@ test02()
   path p3("foo");
   VERIFY( absolute(p3) != p3 );
   VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) );
+#endif
 }
 
 int
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
index 89cec15e7df..f7b6649adfe 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
@@ -41,7 +41,7 @@ test01()
   VERIFY( !ec );
 
   ec = bad_ec;
-  p2 = canonical( fs::current_path() / "." / (p.native() + "////././."), ec );
+  p2 = canonical( fs::current_path() / "." / (p.string() + "////././."), ec );
   compare_paths( p2, fs::current_path()/p );
   VERIFY( !ec );
 
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
index 5fd2407e9e1..f9962ad350b 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
@@ -116,7 +116,7 @@ test03()
   auto to = __gnu_test::nonexistent_path();
 
   // test empty file
-  std::ofstream{from.native()};
+  std::ofstream{from};
   VERIFY( fs::exists(from) );
   VERIFY( fs::file_size(from) == 0 );
   fs::copy(from, to);
@@ -125,7 +125,7 @@ test03()
 
   remove(to);
   VERIFY( !fs::exists(to) );
-  std::ofstream{from.native()} << "Hello, filesystem!";
+  std::ofstream{from} << "Hello, filesystem!";
   VERIFY( fs::file_size(from) != 0 );
   fs::copy(from, to);
   VERIFY( fs::exists(to) );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
index 819dc08b734..495e8d6ad04 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
@@ -42,7 +42,7 @@ test01()
   VERIFY( !exists(to) );
 
   // test empty file
-  std::ofstream{from.native()};
+  std::ofstream{from};
   VERIFY( exists(from) );
   VERIFY( file_size(from) == 0 );
 
@@ -58,7 +58,7 @@ test01()
   VERIFY( exists(to) );
   VERIFY( file_size(to) == 0 );
 
-  std::ofstream{from.native()} << "Hello, filesystem!";
+  std::ofstream{from} << "Hello, filesystem!";
   VERIFY( file_size(from) != 0 );
   remove(to);
   VERIFY( !exists(to) );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
index d73ff35a539..f8a4a280537 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
@@ -29,19 +29,20 @@ void
 test01()
 {
   const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  const path root = __gnu_test::root_path();
 
-  VERIFY( exists(path{"/"}) );
-  VERIFY( exists(path{"/."}) );
+  VERIFY( exists(root) );
+  VERIFY( exists(root/".") );
   VERIFY( exists(path{"."}) );
   VERIFY( exists(path{".."}) );
   VERIFY( exists(std::filesystem::current_path()) );
 
   std::error_code ec;
   ec = bad_ec;
-  VERIFY( exists(path{"/"}, ec) );
+  VERIFY( exists(root, ec) );
   VERIFY( !ec );
   ec = bad_ec;
-  VERIFY( exists(path{"/."}, ec) );
+  VERIFY( exists(root/".", ec) );
   VERIFY( !ec );
   ec = bad_ec;
   VERIFY( exists(path{"."}, ec) );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
index d57529b65f2..ef0e01de4a2 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
@@ -82,7 +82,7 @@ test02()
   empty = is_empty(f.path);
   VERIFY( empty );
 
-  std::ofstream{f.path.native()} << "data";
+  std::ofstream{f.path} << "data";
   ec = bad_ec;
   empty = is_empty(p, ec);
   VERIFY( !ec );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
index 1fdf39c7e0d..ff19afc12a0 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
@@ -81,7 +81,7 @@ test01()
   ::utimbuf times;
   times.modtime = std::numeric_limits<std::time_t>::max() - 1;
   times.actime = std::numeric_limits<std::time_t>::max() - 1;
-  VERIFY( !::utime(p.c_str(), &times) );
+  VERIFY( !::utime(p.string().c_str(), &times) );
 #else
   return;
 #endif
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
index 3d64342fb8f..79e3c7d9b73 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
@@ -25,25 +25,35 @@
 #include <testsuite_fs.h>
 #include <testsuite_hooks.h>
 
+bool check(std::filesystem::space_info const& s)
+{
+  const std::uintmax_t err = -1;
+  return s.capacity != err || s.free != err || s.available != err;
+}
+
 void
 test01()
 {
-  std::filesystem::space_info s = std::filesystem::space("/");
+  const std::filesystem::path root = __gnu_test::root_path();
+  std::filesystem::space_info s = std::filesystem::space(root);
   std::error_code ec = make_error_code(std::errc::invalid_argument);
-  s = std::filesystem::space("/", ec);
+  s = std::filesystem::space(root, ec);
   VERIFY( !ec );
+  VERIFY( check(s) );
+  VERIFY( s.capacity >= s.free );
 
-  s = std::filesystem::space(__gnu_test::nonexistent_path(), ec);
-  VERIFY( ec );
-  VERIFY( s.capacity ==  static_cast<uintmax_t>(-1) );
-  VERIFY( s.free ==  static_cast<uintmax_t>(-1) );
-  VERIFY( s.available ==  static_cast<uintmax_t>(-1) );
+  s = std::filesystem::space(__gnu_test::nonexistent_path()/".", ec);
+  if (ec)
+    VERIFY( ! check(s) );
+  else
+    VERIFY( check(s) );
 }
 
 void
 test02()
 {
   std::filesystem::space_info s = std::filesystem::space(".");
+  VERIFY( check(s) );
   VERIFY( s.capacity >= s.free );
 }
 
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
index f1fe32c8e5e..f9197ac70da 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
@@ -27,10 +27,28 @@
 void
 clean_env()
 {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  ::_putenv("TMP=");
+  ::_putenv("TEMP=");
+#else
   ::unsetenv("TMPDIR");
   ::unsetenv("TMP");
   ::unsetenv("TEMPDIR");
   ::unsetenv("TEMP");
+#endif
+}
+
+bool
+set_env(const char* name, std::string value)
+{
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  std::string s = name;
+  s += '=';
+  s += value;
+  return !::_putenv(s.c_str());
+#else
+  return !::setenv(name, value.c_str(), 1);
+#endif
 }
 
 namespace fs = std::filesystem;
@@ -57,7 +75,7 @@ test02()
 {
   clean_env();
 
-  if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
+  if (!set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
     return; // just give up
 
   std::error_code ec;
@@ -80,7 +98,7 @@ test03()
   auto p = __gnu_test::nonexistent_path();
   create_directories(p/"tmp");
   permissions(p, fs::perms::none);
-  setenv("TMPDIR", (p/"tmp").c_str(), 1);
+  set_env("TMPDIR", (p/"tmp").string());
   std::error_code ec;
   auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
   VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
@@ -102,7 +120,7 @@ void
 test04()
 {
   __gnu_test::scoped_file f;
-  setenv("TMPDIR", f.path.c_str(), 1);
+  set_env("TMPDIR", f.path.string());
   std::error_code ec;
   auto r = fs::temp_directory_path(ec);
   VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
index 0330bcf6c88..2295e1b0e2f 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
@@ -55,6 +55,10 @@ test01()
 
   compare_paths( append("dir/", "/file"), "/file" );
   compare_paths( append("dir/", "file"),  "dir/file" );
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  compare_paths( append("c:/foo", "/bar"),  "c:/bar" );
+#endif
 }
 
 void
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/format.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/format.cc
index a793451aada..bd36e2842b6 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/format.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/format.cc
@@ -30,7 +30,7 @@ void
 test01()
 {
   // path(string_type&&, format)
-  auto s = [&]() -> path::string_type { return "foo/bar"; };
+  auto s = [&]() -> path::string_type { return path("foo/bar").native(); };
   path p0(s());
   path p1(s(), path::auto_format);
   VERIFY( p1 == p0 );
@@ -44,7 +44,7 @@ void
 test02()
 {
   // path(const Source&, format)
-  path::string_type s = "foo/bar";
+  const path::string_type s = path("foo/bar").native();
   path p0(s);
   path p1(s, path::auto_format);
   VERIFY( p1 == p0 );
@@ -58,7 +58,7 @@ void
 test03()
 {
   // path(const Source&, format)
-  std::string s = "foo/bar";
+  const std::string s = "foo/bar";
   path p0(s);
   path p1(s, path::auto_format);
   VERIFY( p1 == p0 );
@@ -73,7 +73,7 @@ test04()
 {
 #ifdef _GLIBCXX_USE_WCHAR_T
   // path(const Source&, format)
-  std::wstring s = L"foo/bar";
+  const std::wstring s = L"foo/bar";
   path p0(s);
   path p1(s, path::auto_format);
   VERIFY( p1 == p0 );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
index c32c647e167..dd696dea57a 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
@@ -31,7 +31,11 @@ void
 test01()
 {
   path p("/foo/bar", std::locale::classic());
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  VERIFY( p.native() == L"/foo/bar" );
+#else
   VERIFY( p.native() == "/foo/bar" );
+#endif
 }
 
 void
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
index 8e6db4f67e2..da5f377de94 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
@@ -47,7 +47,12 @@ test02()
   {
     path rootdir = p.root_directory();
     VERIFY( !rootdir.has_relative_path() );
-    VERIFY( rootdir.empty() || rootdir.native() == "/");
+    if (!rootdir.empty())
+#if defined(__MINGW32__) || defined(__MINGW64__)
+      VERIFY( rootdir.string() == "/" || rootdir.string() == "\\" );
+#else
+      VERIFY( rootdir.string() == "/" );
+#endif
   }
 }
 
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
index 756085c932e..29eab0ad56c 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
@@ -35,7 +35,7 @@ test01()
   path p = "foo.bar.baz.tar";
   std::vector<std::string> v;
   for (; !p.extension().empty(); p = p.stem())
-    v.push_back(p.extension().native());
+    v.push_back(p.extension().string());
   VERIFY( v.at(0) == ".tar" );
   VERIFY( v.at(1) == ".baz" );
   VERIFY( v.at(2) == ".bar" );
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
index c23cb14fd73..4852c03c78e 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
@@ -81,6 +81,24 @@ test01()
   v2 = { "//rootname", "/", "dir", "filename" };
 #else
   v2 = { "/", "rootname", "dir", "filename" };
+#endif
+  VERIFY( v == v2 );
+
+  p = "c:relative/path";
+  v.assign(p.begin(), p.end());
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  v2 = { "c:", "relative", "path" };
+#else
+  v2 = { "c:relative", "path" };
+#endif
+  VERIFY( v == v2 );
+
+  p = "c:/absolute/path";
+  v.assign(p.begin(), p.end());
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  v2 = { "c:", "/", "absolute", "path" };
+#else
+  v2 = { "c:", "absolute", "path" };
 #endif
   VERIFY( v == v2 );
 }
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
index dc4c8b84548..6ae49bb6060 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
@@ -27,14 +27,15 @@ void
 test01()
 {
   using namespace std::filesystem;
-  const std::string s = "abc";
+  using string_type = std::basic_string<path::value_type>;
+  const string_type s{ 'a', 'b', 'c' };
   path p(s);
 
   VERIFY( p.native() == s );
   VERIFY( p.c_str() == s );
-  VERIFY( static_cast<std::string>(p) == s );
+  VERIFY( static_cast<string_type>(p) == s );
 
-  std::string s2 = p; // implicit conversion
+  string_type s2 = p; // implicit conversion
   VERIFY( s2 == p.native() );
 }
 
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_absolute.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_absolute.cc
index 6b5c098489a..16fb1910feb 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_absolute.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_absolute.cc
@@ -29,11 +29,17 @@ using std::filesystem::path;
 void
 test01()
 {
-  VERIFY( path("/").is_absolute() );
-  VERIFY( path("/foo").is_absolute() );
-  VERIFY( path("/foo/").is_absolute() );
-  VERIFY( path("/foo/bar").is_absolute() );
-  VERIFY( path("/foo/bar/").is_absolute() );
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  const bool is_posix = false;
+#else
+  const bool is_posix = true;
+#endif
+
+  VERIFY( path("/").is_absolute() == is_posix );
+  VERIFY( path("/foo").is_absolute() == is_posix );
+  VERIFY( path("/foo/").is_absolute() == is_posix );
+  VERIFY( path("/foo/bar").is_absolute() == is_posix );
+  VERIFY( path("/foo/bar/").is_absolute() == is_posix );
   VERIFY( ! path("foo").is_absolute() );
   VERIFY( ! path("foo/").is_absolute() );
   VERIFY( ! path("foo/bar").is_absolute() );
@@ -43,16 +49,11 @@ test01()
   VERIFY( ! path("c:foo/").is_absolute() );
   VERIFY( ! path("c:foo/bar").is_absolute() );
   VERIFY( ! path("c:foo/bar/").is_absolute() );
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  const bool drive_letter_is_root_name = true;
-#else
-  const bool drive_letter_is_root_name = false;
-#endif
-  VERIFY( path("c:/").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/bar").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/bar/").is_absolute() == drive_letter_is_root_name );
+  VERIFY( path("c:/").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/bar").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/bar/").is_absolute() == !is_posix );
 }
 
 int
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc b/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
index 6199620c4db..fe3d981d295 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
@@ -44,15 +44,16 @@ test01()
   VERIFY( iter == end(iter) );
 
   // Test non-empty directory.
-  create_directory_symlink(p, p / "l", ec);
+  create_directory(p / "x", ec);
   VERIFY( !ec );
   iter = fs::directory_iterator(p, ec);
   VERIFY( !ec );
   VERIFY( iter != fs::directory_iterator() );
-  VERIFY( iter->path() == p/"l" );
+  VERIFY( iter->path() == p/"x" );
   ++iter;
   VERIFY( iter == end(iter) );
 
+#if !(defined(__MINGW32__) || defined(__MINGW64__))
   // Test inaccessible directory.
   permissions(p, fs::perms::none, ec);
   VERIFY( !ec );
@@ -65,6 +66,7 @@ test01()
   iter = fs::directory_iterator(p, opts, ec);
   VERIFY( !ec );
   VERIFY( iter == end(iter) );
+#endif
 
   permissions(p, fs::perms::owner_all, ec);
   remove_all(p, ec);
@@ -76,7 +78,7 @@ test02()
   std::error_code ec;
   const auto p = __gnu_test::nonexistent_path();
   create_directory(p, fs::current_path(), ec);
-  create_directory_symlink(p, p / "l", ec);
+  create_directory(p / "x", ec);
   VERIFY( !ec );
 
   // Test post-increment (libstdc++/71005)
@@ -86,7 +88,7 @@ test02()
   const auto entry1 = *iter;
   const auto entry2 = *iter++;
   VERIFY( entry1 == entry2 );
-  VERIFY( entry1.path() == p/"l" );
+  VERIFY( entry1.path() == p/"x" );
   VERIFY( iter == end(iter) );
 
   remove_all(p, ec);
@@ -121,7 +123,7 @@ test05()
 {
   auto p = __gnu_test::nonexistent_path();
   create_directory(p);
-  create_directory_symlink(p, p / "l");
+  create_directory(p / "x");
   fs::directory_iterator it(p), endit;
   VERIFY( begin(it) == it );
   static_assert( noexcept(begin(it)), "begin is noexcept" );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/absolute.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/absolute.cc
index 753e54d33ef..e493c5be009 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/absolute.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/absolute.cc
@@ -31,12 +31,29 @@ void
 test01()
 {
   for (const path& p : __gnu_test::test_paths)
+  {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+    if (p.empty())
+      continue;
+#endif
     VERIFY( absolute(p).is_absolute() );
+  }
 }
 
 void
 test02()
 {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  path p1("/");
+  VERIFY( absolute(p1) != p1 );
+  path p2("/foo");
+  VERIFY( absolute(p2) != p2 );
+  path p3("foo");
+  VERIFY( absolute(p3) != p3 );
+  path p4("C:\\");
+  VERIFY( absolute(p3, p4) == "C:\\foo" );
+  VERIFY( absolute(p4) == p4 );
+#else
   path p1("/");
   VERIFY( absolute(p1) == p1 );
   VERIFY( absolute(p1, "/bar") == p1 );
@@ -46,6 +63,7 @@ test02()
   path p3("foo");
   VERIFY( absolute(p3) != p3 );
   VERIFY( absolute(p3, "/bar") == "/bar/foo" );
+#endif
 }
 
 int
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
index 6568a6d9c76..1daf908438b 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
@@ -114,7 +114,7 @@ test03()
   auto to = __gnu_test::nonexistent_path();
 
   // test empty file
-  std::ofstream{from.native()};
+  std::ofstream{from.c_str()};
   VERIFY( fs::exists(from) );
   VERIFY( fs::file_size(from) == 0 );
   fs::copy(from, to);
@@ -123,7 +123,7 @@ test03()
 
   remove(to);
   VERIFY( !fs::exists(to) );
-  std::ofstream{from.native()} << "Hello, filesystem!";
+  std::ofstream{from.c_str()} << "Hello, filesystem!";
   VERIFY( fs::file_size(from) != 0 );
   fs::copy(from, to);
   VERIFY( fs::exists(to) );
@@ -150,9 +150,9 @@ test04()
   }
 
   __gnu_test::scoped_file f1(from/"a/f1");
-  std::ofstream{f1.path} << "file one";
+  std::ofstream{f1.path.c_str()} << "file one";
   __gnu_test::scoped_file f2(from/"a/b/f2");
-  std::ofstream{f2.path} << "file two";
+  std::ofstream{f2.path.c_str()} << "file two";
 
   copy(from, to, ec);
   VERIFY( !ec );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
index d529d0654bc..cf4cd4b02a8 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
@@ -42,7 +42,7 @@ test01()
   VERIFY( !exists(to) );
 
   // test empty file
-  std::ofstream{from.native()};
+  std::ofstream{from.c_str()};
   VERIFY( exists(from) );
   VERIFY( file_size(from) == 0 );
 
@@ -58,7 +58,7 @@ test01()
   VERIFY( exists(to) );
   VERIFY( file_size(to) == 0 );
 
-  std::ofstream{from.native()} << "Hello, filesystem!";
+  std::ofstream{from.c_str()} << "Hello, filesystem!";
   VERIFY( file_size(from) != 0 );
   remove(to);
   VERIFY( !exists(to) );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
index c4b6ebf0662..c21a87124d0 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
@@ -28,16 +28,18 @@ using std::experimental::filesystem::path;
 void
 test01()
 {
-  VERIFY( exists(path{"/"}) );
-  VERIFY( exists(path{"/."}) );
+  const path root = __gnu_test::root_path();
+
+  VERIFY( exists(root) );
+  VERIFY( exists(root/".") );
   VERIFY( exists(path{"."}) );
   VERIFY( exists(path{".."}) );
   VERIFY( exists(std::experimental::filesystem::current_path()) );
 
   std::error_code ec = std::make_error_code(std::errc::invalid_argument);
-  VERIFY( exists(path{"/"}, ec) );
+  VERIFY( exists(root, ec) );
   VERIFY( !ec );
-  VERIFY( exists(path{"/."}, ec) );
+  VERIFY( exists(root/".", ec) );
   VERIFY( !ec );
   VERIFY( exists(path{"."}, ec) );
   VERIFY( !ec );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc
index 14b2bcea071..17a174f6af6 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc
@@ -82,7 +82,7 @@ test02()
   empty = is_empty(f.path);
   VERIFY( empty );
 
-  std::ofstream{f.path.native()} << "data";
+  std::ofstream{f.path.c_str()} << "data";
   ec = bad_ec;
   empty = is_empty(p, ec);
   VERIFY( !ec );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
index 9d1752fd4fc..d0be9028b04 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
@@ -81,7 +81,7 @@ test01()
   ::utimbuf times;
   times.modtime = std::numeric_limits<std::time_t>::max() - 1;
   times.actime = std::numeric_limits<std::time_t>::max() - 1;
-  VERIFY( !::utime(p.c_str(), &times) );
+  VERIFY( !::utime(p.string().c_str(), &times) );
 #else
   return;
 #endif
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/space.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/space.cc
index aa6a6aeaa60..2ccf5014c3a 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/space.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/space.cc
@@ -30,9 +30,10 @@ namespace fs = std::experimental::filesystem;
 void
 test01()
 {
-  fs::space_info s = fs::space("/");
+  const fs::path root = __gnu_test::root_path();
+  fs::space_info s = fs::space(root);
   std::error_code ec = make_error_code(std::errc::invalid_argument);
-  s = fs::space("/", ec);
+  s = fs::space(root, ec);
   VERIFY( !ec );
 
   s = fs::space(__gnu_test::nonexistent_path(), ec);
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
index 7e60b3fa442..1e98049d043 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
@@ -27,10 +27,28 @@
 void
 clean_env()
 {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  ::_putenv("TMP=");
+  ::_putenv("TEMP=");
+#else
   ::unsetenv("TMPDIR");
   ::unsetenv("TMP");
   ::unsetenv("TEMPDIR");
   ::unsetenv("TEMP");
+#endif
+}
+
+bool
+set_env(const char* name, std::string value)
+{
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  std::string s = name;
+  s += '=';
+  s += value;
+  return !::_putenv(s.c_str());
+#else
+  return !::setenv(name, value.c_str(), 1);
+#endif
 }
 
 namespace fs = std::experimental::filesystem;
@@ -57,7 +75,7 @@ test02()
 {
   clean_env();
 
-  if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
+  if (set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
     return; // just give up
 
   std::error_code ec;
@@ -80,7 +98,7 @@ test03()
   auto p = __gnu_test::nonexistent_path();
   create_directories(p/"tmp");
   permissions(p, fs::perms::none);
-  setenv("TMPDIR", (p/"tmp").c_str(), 1);
+  set_env("TMPDIR", (p/"tmp").string());
   std::error_code ec;
   auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
   VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
@@ -102,7 +120,7 @@ void
 test04()
 {
   __gnu_test::scoped_file f;
-  setenv("TMPDIR", f.path.c_str(), 1);
+  set_env("TMPDIR", f.path.string());
   std::error_code ec;
   auto r = fs::temp_directory_path(ec);
   VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/append/path.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/append/path.cc
index 52c83cf92d3..5e8b330e18d 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/append/path.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/append/path.cc
@@ -34,16 +34,20 @@ test01()
 
   path pp = p;
   pp /= p;
-  VERIFY( pp.native() == "/foo/bar/foo/bar" );
+  VERIFY( pp.string() == "/foo/bar/foo/bar" );
 
   path q("baz");
 
   path qq = q;
   qq /= q;
-  VERIFY( qq.native() == "baz/baz" );
+#if defined(__MINGW32__) || defined(__MINGW64__)
+  VERIFY( qq.string() == "baz\\baz" );
+#else
+  VERIFY( qq.string() == "baz/baz" );
+#endif
 
   q /= p;
-  VERIFY( q.native() == "baz/foo/bar" );
+  VERIFY( q.string() == "baz/foo/bar" );
 
   path r = "";
   r /= path();
@@ -54,7 +58,7 @@ test01()
 
   path s = "dir/";
   s /= path("/file");
-  VERIFY( s.native() == "dir//file" );
+  VERIFY( s.string() == "dir//file" );
 }
 
 int
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/concat/path.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/path.cc
index 31bdcb9f1dc..8f11254b7e2 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/concat/path.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/concat/path.cc
@@ -34,18 +34,18 @@ test01()
 
   path pp = p;
   pp += p;
-  VERIFY( pp.native() == "/foo/bar/foo/bar" );
+  VERIFY( pp.string() == "/foo/bar/foo/bar" );
   VERIFY( std::distance(pp.begin(), pp.end()) == 5 );
 
   path q("foo/bar");
 
   path qq = q;
   qq += q;
-  VERIFY( qq.native() == "foo/barfoo/bar" );
+  VERIFY( qq.string() == "foo/barfoo/bar" );
   VERIFY( std::distance(qq.begin(), qq.end()) == 3 );
 
   q += p;
-  VERIFY( q.native() == "foo/bar/foo/bar" );
+  VERIFY( q.string() == "foo/bar/foo/bar" );
   VERIFY( std::distance(q.begin(), q.end()) == 4 );
 }
 
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/root_directory.cc
index 535610f4e8f..fc38be6adf1 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/root_directory.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/root_directory.cc
@@ -48,8 +48,8 @@ test02()
     path rootdir = p.root_directory();
     // If root-directory is composed of 'slash name',
     // 'slash' is excluded from the returned string.
-    if (!rootdir.empty() && rootdir.native() != "/")
-      VERIFY( rootdir.native()[0] != '/' );
+    if (!rootdir.empty() && rootdir.string() != "/")
+      VERIFY( rootdir.string()[0] != '/' );
   }
 }
 
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/stem.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/stem.cc
index 088c4ec4b35..0f67e02a112 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/stem.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/stem.cc
@@ -35,7 +35,7 @@ test01()
   path p = "foo.bar.baz.tar";
   std::vector<std::string> v;
   for (; !p.extension().empty(); p = p.stem())
-    v.push_back(p.extension().native());
+    v.push_back(p.extension().string());
   VERIFY( v.at(0) == ".tar" );
   VERIFY( v.at(1) == ".baz" );
   VERIFY( v.at(2) == ".bar" );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/native/string.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/native/string.cc
index bd353ae5e19..8e40cdb0e1e 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/native/string.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/native/string.cc
@@ -27,14 +27,15 @@ void
 test01()
 {
   using namespace std::experimental::filesystem;
-  const std::string s = "abc";
+  using string_type = std::basic_string<path::value_type>;
+  const string_type s{ 'a', 'b', 'c' };
   path p(s);
 
   VERIFY( p.native() == s );
   VERIFY( p.c_str() == s );
-  VERIFY( static_cast<std::string>(p) == s );
+  VERIFY( static_cast<string_type>(p) == s );
 
-  std::string s2 = p; // implicit conversion
+  string_type s2 = p; // implicit conversion
   VERIFY( s2 == p.native() );
 }
 
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/query/is_absolute.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/query/is_absolute.cc
index 1b99eaceef4..974dec4381d 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/query/is_absolute.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/query/is_absolute.cc
@@ -29,11 +29,17 @@ using std::filesystem::path;
 void
 test01()
 {
-  VERIFY( path("/").is_absolute() );
-  VERIFY( path("/foo").is_absolute() );
-  VERIFY( path("/foo/").is_absolute() );
-  VERIFY( path("/foo/bar").is_absolute() );
-  VERIFY( path("/foo/bar/").is_absolute() );
+  #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  const bool is_posix = false;
+#else
+  const bool is_posix = true;
+#endif
+
+  VERIFY( path("/").is_absolute() == is_posix );
+  VERIFY( path("/foo").is_absolute() == is_posix );
+  VERIFY( path("/foo/").is_absolute() == is_posix );
+  VERIFY( path("/foo/bar").is_absolute() == is_posix );
+  VERIFY( path("/foo/bar/").is_absolute() == is_posix );
   VERIFY( ! path("foo").is_absolute() );
   VERIFY( ! path("foo/").is_absolute() );
   VERIFY( ! path("foo/bar").is_absolute() );
@@ -43,16 +49,11 @@ test01()
   VERIFY( ! path("c:foo/").is_absolute() );
   VERIFY( ! path("c:foo/bar").is_absolute() );
   VERIFY( ! path("c:foo/bar/").is_absolute() );
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-  const bool drive_letter_is_root_name = true;
-#else
-  const bool drive_letter_is_root_name = false;
-#endif
-  VERIFY( path("c:/").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/bar").is_absolute() == drive_letter_is_root_name );
-  VERIFY( path("c:/foo/bar/").is_absolute() == drive_letter_is_root_name );
+  VERIFY( path("c:/").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/bar").is_absolute() == !is_posix );
+  VERIFY( path("c:/foo/bar/").is_absolute() == !is_posix );
 }
 
 int
diff --git a/libstdc++-v3/testsuite/util/testsuite_fs.h b/libstdc++-v3/testsuite/util/testsuite_fs.h
index 5a9cdac2f83..eccb8929d7d 100644
--- a/libstdc++-v3/testsuite/util/testsuite_fs.h
+++ b/libstdc++-v3/testsuite/util/testsuite_fs.h
@@ -73,6 +73,16 @@ namespace __gnu_test
     "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
   };
 
+  test_fs::path
+  root_path()
+  {
+#if defined(__MING32__) || defined(__MINGW64__)
+    return L"c:/";
+#else
+    return "/";
+#endif
+  }
+
   // This is NOT supposed to be a secure way to get a unique name!
   // We just need a path that doesn't exist for testing purposes.
   test_fs::path
@@ -111,7 +121,7 @@ namespace __gnu_test
 
     explicit
     scoped_file(const path_type& p = nonexistent_path()) : path(p)
-    { std::ofstream{p.native()}; }
+    { std::ofstream{p.c_str()}; }
 
     scoped_file(path_type p, adopt_file_t) : path(p) { }
 


More information about the Gcc-patches mailing list