On 01/05/15 11:53 +0100, Jonathan Wakely wrote:
On 01/05/15 10:05 +0900, Luke Allardyce wrote:
This fails on mingw-w64 4.02 due to

Yay, thanks for trying it!

an extra typename:

/mnt/build/native/gcc/x86_64-w64-mingw32/libstdc++-v3/include/experimental/fs_path.h:784:35:
error: expected nested-name-specifier
     using _CharAlloc = typename __alloc_rebind<_Allocator, char>;

Oops, forgetting how to use my own alias.


readdir_r not available:

/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:169:46: error:
'readdir_r' was not declared in this scope
 if (int err = readdir_r(dirp, &ent, &result))


and calling opendir with a wchar_t*

/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:108:40: error: cannot
convert 'const value_type* {aka const wchar_t*}' to 'const char*' for
argument '1' to 'DIR* opendir(const char*)'
   if (DIR* dirp = ::opendir(p.c_str()))

/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:256:38: error: cannot
convert 'const value_type* {aka const wchar_t*}' to 'const char*' for
argument '1' to 'DIR* opendir(const char*)'
 if (DIR* dirp = ::opendir(p.c_str()))

Ah interesting, this means mingw supports <dirent.h>, I was expecting
it to use the dummy definitions at the top of src/filesystem/dir.cc
(where I'd made opendir take wchar_t).

I've done some reading and am going to commit some fixes and
improvements for mingw in an hour or two. It would be great if you
could try it again after that.

I've committed the two changes attached (only tested on linux again).

patch2.txt should fix the mingw-w64 errors above, as well as the
issues Daniel reported, and should fix the error on Solaris 10

Rainer, would you be able to test with
--enable-libstdcxx-filesystem-ts before we re-enable it to build by
default on solaris* ?


patch1.txt changes path::_M_cmpts from std::list to std::vector (as
Marc suggested months ago) and fixes the pretty printer, so paths are
shown like this in GDB:

(gdb) print p
$1 = filesystem::path ""
(gdb) print c
$2 = filesystem::path "/home/jwakely" = {[root-directory] = "/", [1] = "home", [2] = 
"jwakely"}
(gdb) print r
$3 = filesystem::path "/" [root-directory]
(gdb) print h
$4 = filesystem::path "home"
(gdb) print l
$5 = filesystem::path "//host/foo/bar///baz/.//xyzzy/meta/syntactic/variable" = {[root-name] = "//host", [root-directory] = "/", [2] = "foo", [3] = 
"bar", [4] = "baz", [5] = ".", [6] = "xyzzy", [7] = "meta", [8] = "syntactic", [9] = "variable"}

That output came from debugging this code:

 path p;
 path c = current_path();
 path r = *c.begin();
 path h = *std::next(c.begin());
 path l = "//host/foo/bar///baz/.//xyzzy/meta/syntactic/variable";


Thanks everyone for testing and feedback, it's been very helpful.
commit 44990ad8ae2cafab954b9e64556fc2ca0db97d7e
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Fri May 1 13:41:42 2015 +0100

        * include/experimental/fs_path.h (path::_List): Use vector instead of
        list.
        * python/libstdcxx/v6/printers.py (StdExpPathPrinter): Adapt.
        * src/filesystem/path.cc: Use std::prev instead of decrementing
        rvalues. Fix whitespace.
        * testsuite/experimental/filesystem/path/decompose/parent_path.cc:
        Do not decrement iterators before begin.

diff --git a/libstdc++-v3/include/experimental/fs_path.h 
b/libstdc++-v3/include/experimental/fs_path.h
index 11b0561..e57a08b 100644
--- a/libstdc++-v3/include/experimental/fs_path.h
+++ b/libstdc++-v3/include/experimental/fs_path.h
@@ -36,7 +36,7 @@
 
 #include <utility>
 #include <type_traits>
-#include <list>
+#include <vector>
 #include <locale>
 #include <iosfwd>
 #include <codecvt>
@@ -430,7 +430,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     string_type _M_pathname;
 
     struct _Cmpt;
-    using _List = std::list<_Cmpt>;
+    using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
     _List _M_cmpts; // empty unless _M_type == _Type::_Multi
     _Type _M_type = _Type::_Multi;
   };
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py 
b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 37c3b9b..c6f96d7 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -984,16 +984,51 @@ class StdExpPathPrinter:
 
     def __init__ (self, typename, val):
         self.val = val
-        self.list_visualizer = gdb.default_visualizer(val['_M_cmpts'])
+        start = self.val['_M_cmpts']['_M_impl']['_M_start']
+        finish = self.val['_M_cmpts']['_M_impl']['_M_finish']
+        self.num_cmpts = int (finish - start)
+
+    def _path_type(self):
+        t = str(self.val['_M_type'])
+        if t[-9:] == '_Root_dir':
+            return "root-directory"
+        if t[-10:] == '_Root_name':
+            return "root-name"
+        return None
 
     def to_string (self):
-        path = self.val ['_M_pathname']
-        if self.list_visualizer:
-            list_head = self.val['_M_cmpts']['_M_impl']['_M_node']
-            if list_head.address != list_head['_M_next']:
-                cmpts = self.list_visualizer.to_string()
-                path = "%s [Components %s]" % (path, cmpts)
-        return path
+        path = "%s" % self.val ['_M_pathname']
+        if self.num_cmpts == 0:
+            t = self._path_type()
+            if t:
+                path = '%s [%s]' % (path, t)
+        return "filesystem::path %s" % path
+
+    class _iterator(Iterator):
+        def __init__(self, cmpts):
+            self.item = cmpts['_M_impl']['_M_start']
+            self.finish = cmpts['_M_impl']['_M_finish']
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def __next__(self):
+            if self.item == self.finish:
+                raise StopIteration
+            item = self.item.dereference()
+            count = self.count
+            self.count = self.count + 1
+            self.item = self.item + 1
+            path = item['_M_pathname']
+            t = StdExpPathPrinter(item.type.name, item)._path_type()
+            if not t:
+                t = count
+            return ('[%s]' % t, path)
+
+    def children(self):
+        return self._iterator(self.val['_M_cmpts'])
+
 
 # A "regular expression" printer which conforms to the
 # "SubPrettyPrinter" protocol from gdb.printing.
@@ -1383,7 +1418,7 @@ def build_libstdcxx_dictionary ():
     # Filesystem TS components
     libstdcxx_printer.add_version('std::experimental::filesystem::v1::',
                                   'path', StdExpPathPrinter)
-    libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11',
+    
libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
                                   'path', StdExpPathPrinter)
 
     # Extensions.
diff --git a/libstdc++-v3/src/filesystem/path.cc 
b/libstdc++-v3/src/filesystem/path.cc
index db58f3b..cc5780f 100644
--- a/libstdc++-v3/src/filesystem/path.cc
+++ b/libstdc++-v3/src/filesystem/path.cc
@@ -35,7 +35,7 @@ path::remove_filename()
     {
       if (!_M_cmpts.empty())
        {
-         auto cmpt = --_M_cmpts.end();
+         auto cmpt = std::prev(_M_cmpts.end());
          _M_pathname.erase(cmpt->_M_pos);
          _M_cmpts.erase(cmpt);
          _M_trim();
@@ -109,7 +109,7 @@ path::compare(const path& p) const noexcept
 {
   if (_M_type == _Type::_Multi && p._M_type == _Type::_Multi)
     return do_compare(_M_cmpts.begin(), _M_cmpts.end(),
-                  p._M_cmpts.begin(), p._M_cmpts.end());
+                     p._M_cmpts.begin(), p._M_cmpts.end());
   else if (_M_type == _Type::_Multi)
     {
       _Cmpt c[1] = { { p._M_pathname, p._M_type, 0 } };
@@ -130,8 +130,7 @@ path::root_name() const
   path __ret;
   if (_M_type == _Type::_Root_name)
     __ret = *this;
-  else if (_M_cmpts.size()
-      && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+  else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
     __ret = *_M_cmpts.begin();
   return __ret;
 }
@@ -203,8 +202,8 @@ path::parent_path() const
   path __ret;
   if (_M_cmpts.size() < 2)
     return __ret;
-  for (auto __it = _M_cmpts.begin(), __end = --_M_cmpts.end();
-      __it != __end; ++__it)
+  for (auto __it = _M_cmpts.begin(), __end = std::prev(_M_cmpts.end());
+       __it != __end; ++__it)
     {
       __ret /= *__it;
     }
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
index 2c21f6f..41df1bf 100644
--- 
a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
@@ -44,6 +44,8 @@ test02()
 {
   for (const path& p : __gnu_test::test_paths)
   {
+    if (p.begin() == p.end())
+      continue;
     path pp;
     for (auto i = p.begin(), end = --p.end(); i != end; ++i)
     {
commit e132913c9b82a9d57c4af3df2560dc89279a78a5
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Fri May 1 12:13:06 2015 +0100

        * acinclude.m4 (GLIBCXX_ENABLE_FILESYSTEM_TS): Disable when <dirent.h>
        is not available.
        (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for fchmodat.
        * configure: Regenerate.
        * config.h.in: Regenerate.
        * configure.ac: Check for utime.h
        * include/experimental/fs_path.h (path::string<>)
        [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Remove stray typename keyword.
        * src/filesystem/dir.cc [!_GLIBCXX_HAVE_DIRENT_H] (DIR, opendir,
        closedir, dirent, readdir_r): Replace dummy functions with #error.
        (native_readdir, _Dir::advance): Use readdir when readdir_r is missing.
        * src/filesystem/ops.cc (do_stat, is_set): Make inline.
        (last_write_time) [!_GLIBCXX_USE_UTIMENSAT]: Use utime.
        (permissions) [!_GLIBCXX_USE_FCHMODAT]: Use chmod.
        (space, temp_directory_path) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Set
        error_code.

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 9d8d96d..07b5bd7 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -3914,6 +3914,9 @@ AC_DEFUN([GLIBCXX_ENABLE_FILESYSTEM_TS], [
     [permit yes|no|auto])
 
   AC_MSG_CHECKING([whether to build Filesystem TS support])
+  if test x"$ac_cv_header_dirent_h" != x"yes"; then
+    enable_libstdcxx_filesystem_ts=no
+  fi
   if test x"$enable_libstdcxx_filesystem_ts" = x"auto"; then
     case "${target_os}" in
       freebsd*|netbsd*|openbsd*|dragonfly*|darwin*)
@@ -3993,6 +3996,22 @@ dnl
   fi
   AC_MSG_RESULT($glibcxx_cv_st_mtim)
 dnl
+  AC_MSG_CHECKING([for fchmodat])
+  AC_CACHE_VAL(glibcxx_cv_fchmodat, [dnl
+    GCC_TRY_COMPILE_OR_LINK(
+      [
+        #include <fcntl.h>
+        #include <sys/stat.h>
+      ],
+      [fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW);],
+      [glibcxx_cv_fchmodat=yes],
+      [glibcxx_cv_fchmodat=no])
+  ])
+  if test $glibcxx_cv_fchmodat = yes; then
+    AC_DEFINE(_GLIBCXX_USE_FCHMODAT, 1, [Define if fchmodat is available in 
<sys/stat.h>.])
+  fi
+  AC_MSG_RESULT($glibcxx_cv_fchmodat)
+dnl
   CXXFLAGS="$ac_save_CXXFLAGS"
   AC_LANG_RESTORE
 ])
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 4b39bfa..311baa5 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -403,7 +403,7 @@ GLIBCXX_CONFIGURE_TESTSUITE
 GLIBCXX_CHECK_GTHREADS
 
 # For Filesystem TS.
-AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h])
+AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
 AC_STRUCT_DIRENT_D_TYPE
 GLIBCXX_ENABLE_FILESYSTEM_TS
 GLIBCXX_CHECK_FILESYSTEM_DEPS
diff --git a/libstdc++-v3/include/experimental/fs_path.h 
b/libstdc++-v3/include/experimental/fs_path.h
index e57a08b..33a16db 100644
--- a/libstdc++-v3/include/experimental/fs_path.h
+++ b/libstdc++-v3/include/experimental/fs_path.h
@@ -781,7 +781,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       const value_type* __last = __first + _M_pathname.size();
 
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-      using _CharAlloc = typename __alloc_rebind<_Allocator, char>;
+      using _CharAlloc = __alloc_rebind<_Allocator, char>;
       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
       using _WString = basic_string<_CharT, _Traits, _Allocator>;
 
diff --git a/libstdc++-v3/src/filesystem/dir.cc 
b/libstdc++-v3/src/filesystem/dir.cc
index 4ed869e..016a78d 100644
--- a/libstdc++-v3/src/filesystem/dir.cc
+++ b/libstdc++-v3/src/filesystem/dir.cc
@@ -25,7 +25,6 @@
 #include <experimental/filesystem>
 #include <utility>
 #include <stack>
-#include <tuple>
 #include <string.h>
 #include <errno.h>
 #ifdef _GLIBCXX_HAVE_DIRENT_H
@@ -34,17 +33,12 @@
 # endif
 # include <dirent.h>
 #else
-// TODO: replace dummy definitions with suitable Win32 code
-#ifndef EACCES
-# define EACCES static_cast<int>(std::errc::permission_denied)
+# error "the <dirent.h> header is needed to build the Filesystem TS"
 #endif
-using DIR = void;
-using P = std::experimental::filesystem::path;
-static DIR* opendir(const P::value_type*) { return nullptr; }
-static void closedir(DIR*) { }
-struct dirent { const char* d_name; };
-static inline int readdir_r(DIR*, dirent*, dirent**)
-{ return static_cast<int>(std::errc::not_supported); }
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef opendir
+# define opendir _wopendir
 #endif
 
 namespace fs = std::experimental::filesystem;
@@ -97,7 +91,7 @@ struct fs::_Dir
 namespace
 {
   template<typename Bitmask>
-    bool is_set(Bitmask obj, Bitmask bits)
+    inline bool is_set(Bitmask obj, Bitmask bits)
     {
       return (obj & bits) != Bitmask::none;
     }
@@ -159,14 +153,27 @@ namespace
     return fs::file_type::none;
 #endif
   }
+
+  int
+  native_readdir(DIR* dirp, ::dirent*& entryp)
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    errno = 0;
+    if ((entryp = ::readdir(dirp)))
+      return 0;
+    return errno;
+#else
+    return ::readdir_r(dirp, entryp, &entryp);
+#endif
+  }
 }
 
 bool
 fs::_Dir::advance(ErrorCode ec)
 {
   ::dirent ent;
-  ::dirent* result;
-  if (int err = readdir_r(dirp, &ent, &result))
+  ::dirent* result = &ent;
+  if (int err = native_readdir(dirp, result))
     {
       if (!ec)
        _GLIBCXX_THROW_OR_ABORT(filesystem_error(
diff --git a/libstdc++-v3/src/filesystem/ops.cc 
b/libstdc++-v3/src/filesystem/ops.cc
index 091ca72..c7e3960 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -47,6 +47,16 @@
 # include <ext/stdio_filebuf.h>
 # include <ostream>
 #endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef utime
+# define utime _wutime
+# undef chmod
+# define chmod _wchmod
+#endif
 
 namespace fs = std::experimental::filesystem;
 
@@ -131,7 +141,7 @@ fs::copy(const path& from, const path& to, copy_options 
options)
 namespace
 {
   template<typename Bitmask>
-    bool is_set(Bitmask obj, Bitmask bits)
+    inline bool is_set(Bitmask obj, Bitmask bits)
     {
       return (obj & bits) != Bitmask::none;
     }
@@ -767,7 +777,7 @@ fs::file_size(const path& p)
 namespace
 {
   template<typename Accessor, typename T>
-    T
+    inline T
     do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
     {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
@@ -871,6 +881,14 @@ fs::last_write_time(const path& p 
__attribute__((__unused__)),
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
+#elif _GLIBCXX_HAVE_UTIME_H
+  ::utimbuf times;
+  times.modtime = s.count();
+  times.actime = do_stat(p, ec, std::mem_fn(&stat::st_atime), times.modtime);
+  if (::utime(p.c_str(), &times))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
 #else
   ec = std::make_error_code(std::errc::not_supported);
 #endif
@@ -887,7 +905,11 @@ fs::permissions(const path& p, perms prms)
 
 void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
 {
+#if _GLIBCXX_USE_FCHMODAT
   if (int err = ::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0))
+#else
+  if (int err = ::chmod(p.c_str(), static_cast<mode_t>(prms)))
+#endif
     ec.assign(err, std::generic_category());
   else
     ec.clear();
@@ -1051,6 +1073,8 @@ fs::space(const path& p, error_code& ec) noexcept
       };
       ec.clear();
     }
+#else
+  ec = std::make_error_code(std::errc::not_supported);
 #endif
   return info;
 }
@@ -1157,6 +1181,7 @@ fs::path fs::temp_directory_path()
 fs::path fs::temp_directory_path(error_code& ec)
 {
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  ec = std::make_error_code(std::errc::not_supported);
   return {}; // TODO
 #else
   const char* tmpdir = ::getenv("TMPDIR");


Reply via email to