From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 36194 invoked by alias); 1 May 2015 19:49:03 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 36175 invoked by uid 89); 1 May 2015 19:49:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 01 May 2015 19:49:00 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t41JmtCb013778 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 1 May 2015 15:48:56 -0400 Received: from localhost (ovpn-116-62.ams2.redhat.com [10.36.116.62]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t41Jmsc5017264; Fri, 1 May 2015 15:48:54 -0400 Date: Fri, 01 May 2015 19:49:00 -0000 From: Jonathan Wakely To: Luke Allardyce Cc: libstdc++ , gcc-patches@gcc.gnu.org, Daniel =?iso-8859-1?Q?Kr=FCgler?= , Rainer Orth Subject: Re: [patch] Implement ISO/IEC TS 18822 C++ File system TS Message-ID: <20150501194853.GK3618@redhat.com> References: <20150430173236.GT3618@redhat.com> <20150430191353.GW3618@redhat.com> <20150501105351.GY3618@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="pkBzO0lo80FoaZii" Content-Disposition: inline In-Reply-To: <20150501105351.GY3618@redhat.com> User-Agent: Mutt/1.5.23 (2014-03-12) X-SW-Source: 2015-05/txt/msg00098.txt.bz2 --pkBzO0lo80FoaZii Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Content-length: 2774 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 , 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. --pkBzO0lo80FoaZii Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch1.txt" Content-length: 6075 commit 44990ad8ae2cafab954b9e64556fc2ca0db97d7e Author: Jonathan Wakely 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 #include -#include +#include #include #include #include @@ -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) { --pkBzO0lo80FoaZii Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch2.txt" Content-length: 7672 commit e132913c9b82a9d57c4af3df2560dc89279a78a5 Author: Jonathan Wakely Date: Fri May 1 12:13:06 2015 +0100 * acinclude.m4 (GLIBCXX_ENABLE_FILESYSTEM_TS): Disable when 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 + #include + ], + [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 .]) + 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, _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 #include #include -#include #include #include #ifdef _GLIBCXX_HAVE_DIRENT_H @@ -34,17 +33,12 @@ # endif # include #else -// TODO: replace dummy definitions with suitable Win32 code -#ifndef EACCES -# define EACCES static_cast(std::errc::permission_denied) +# error "the 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(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 - 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 # include #endif +#if _GLIBCXX_HAVE_UTIME_H +# include +#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 - 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 - 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(), ×)) + 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(prms), 0)) +#else + if (int err = ::chmod(p.c_str(), static_cast(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"); --pkBzO0lo80FoaZii--