This syncs the std::experimental::filesystem code on gcc-6-branch to
match what's on trunk, except that the C++17 std::string_view type
doesn't exist on the branch, so the filesystem::path type only
supports experimental::string_view.

I'm doing it as one big patch, rather than backporting 26 individual
patches.

This implements the following LWG DRs:
2681 2682 2683 2706 2707 2712 2720 2723

        Backport from mainline
        PR libstdc++/70975
        PR libstdc++/71337
        PR libstdc++/78111
        * include/experimental/bits/fs_dir.h (recursive_directory_iterator):
        Overload pop (LWG 2706).
        * include/experimental/bits/fs_fwd.h (perms::resolve_symlinks):
        Replace with symlink_nofollow (LWG 2720).
        * include/experimental/bits/fs_ops.h
        (exists(const path&, error_code&)): Clear error if status is known
        (LWG 2725).
        * include/experimental/bits/fs_path.h (__is_path_src)
        (_S_range_begin, _S_range_end): Overload to treat string_view as a
        Source object.
        (path::operator+=, path::compare): Overload for basic_string_view.
        (path::path(string_type&&))
        (path::operator=(string&&), path::assign(string_type&&)): Define
        construction and assignment from string_type rvalues (LWG 2707).
        (path::_S_convert<_Iter>(_Iter, _Iter)): Remove cv-qualifiers from
        iterator's value_type.
        (path::_S_convert<_Iter>(_Iter __first, __null_terminated)): Likewise.
        Do not use operation not supported by input iterators.
        (path::__is_path_iter_src): Add partial specialization for const
        encoded character types.
        * src/filesystem/dir.cc (open_dir): Return same value for errors
        whether ignored or not.
        (_Dir::advance(error_code*, directory_options)): Return false on
        error.
        (directory_iterator(const path&, directory_options, error_code*)):
        Create end iterator on error (LWG 2723).
        (recursive_directory_iterator(const path&, directory_options,
        error_code*)): Likewise.
        (recursive_directory_iterator::increment): Reset state on error.
        (recursive_directory_iterator::pop): Define new overload.
        * src/filesystem/ops.cc (canonical): Set error for non-existent path.
        (file_time): Take error_code parameter and check for overflow.
        (close_fd): Remove.
        (do_copy_file): Report an error if source or destination is not a
        regular file (LWG 2712). Pass error_code in file_time calls.  Just
        use close(3) instead of close_fd, to prevent retrying on error.
        Check if _GLIBCXX_USE_FCHMODAT is defined.
        [_GLIBCXX_USE_SENDFILE]: Fallback to read/write operations in case
        sendfile fails with ENOSYS or EINVAL. Pass non-null pointer to
        sendfile for offset argument.
        (copy): Update comment to refer to LWG 2681. Implement 2682 and 2683
        resolutions.
        (equivalent): Fix error handling and result when only one file exists.
        (is_empty): Fix error handling.
        (last_write_time(const path&, error_code&)): Pass error_code in
        file_time calls.
        (last_write_time(const path&, file_time_type, error_code&)): Handle
        negative times correctly.
        (permissions(const path&, perms, error_code&)): Handle
        symlink_nofollow.
        (read_symlink): Add missing ec.clear().
        (status(const path&, error_code&)): Handle EOVERFLOW.
        (temp_directory_path): Pass error_code argument to other filesystem
        operations.
        * testsuite/experimental/filesystem/iterators/directory_iterator.cc:
        Update expected behaviour on error.
        * testsuite/experimental/filesystem/iterators/pop.cc: New.
        * testsuite/experimental/filesystem/iterators/
        recursive_directory_iterator.cc: Update expected behaviour on error.
        * testsuite/experimental/filesystem/operations/copy.cc: Update
        expected behaviour for copying directories with create_symlinks.
        Verify that error_code arguments are cleared if there's no error.
        Remove files created by tests. Test copying directories.
        * testsuite/experimental/filesystem/operations/copy_file.cc: Remove
        files created by tests.
        * testsuite/experimental/filesystem/operations/create_symlink.cc: New.
        * testsuite/experimental/filesystem/operations/equivalent.cc: New.
        * testsuite/experimental/filesystem/operations/exists.cc: Test
        overload taking an error_code.
        * testsuite/experimental/filesystem/operations/is_empty.cc: New.
        * testsuite/experimental/filesystem/operations/last_write_time.cc:
        New.
        * testsuite/experimental/filesystem/operations/permissions.cc: Test
        overload taking error_code. Test symlink_nofollow on non-symlinks.
        * testsuite/experimental/filesystem/operations/read_symlink.cc: New.
        * testsuite/experimental/filesystem/operations/remove_all.cc: New.
        * testsuite/experimental/filesystem/operations/temp_directory_path.cc:
        Add testcase for inaccessible directory.
        * testsuite/experimental/filesystem/path/construct/range.cc: Test
        construction from input iterators with const value types.
        * testsuite/experimental/filesystem/path/construct/string_view.cc:
        New.
        * testsuite/util/testsuite_fs.h (scoped_file): Define RAII helper.

Tested x86_64-linux, committed to gcc-6-branch.

I'll backport most of this to gcc-5-branch too, I think the gcc-6
patch should apply cleanly, but I'll need to adjust the tests to not
use { dg-do action { target c++11 } } as that's only on trunk and
gcc-6-branch.

commit 20a4577cefafe57b19990b50f37a4042837d672b
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Mon Dec 12 13:35:06 2016 +0000

    Backport all Filesystem library fixes from trunk
    
    This implements the following LWG DRs:
    2681 2682 2683 2706 2707 2712 2720 2723
    
        Backport from mainline
        PR libstdc++/70975
        PR libstdc++/71337
        PR libstdc++/78111
        * include/experimental/bits/fs_dir.h (recursive_directory_iterator):
        Overload pop (LWG 2706).
        * include/experimental/bits/fs_fwd.h (perms::resolve_symlinks):
        Replace with symlink_nofollow (LWG 2720).
        * include/experimental/bits/fs_ops.h
        (exists(const path&, error_code&)): Clear error if status is known
        (LWG 2725).
        * include/experimental/bits/fs_path.h (__is_path_src)
        (_S_range_begin, _S_range_end): Overload to treat string_view as a
        Source object.
        (path::operator+=, path::compare): Overload for basic_string_view.
        (path::path(string_type&&))
        (path::operator=(string&&), path::assign(string_type&&)): Define
        construction and assignment from string_type rvalues (LWG 2707).
        (path::_S_convert<_Iter>(_Iter, _Iter)): Remove cv-qualifiers from
        iterator's value_type.
        (path::_S_convert<_Iter>(_Iter __first, __null_terminated)): Likewise.
        Do not use operation not supported by input iterators.
        (path::__is_path_iter_src): Add partial specialization for const
        encoded character types.
        * src/filesystem/dir.cc (open_dir): Return same value for errors
        whether ignored or not.
        (_Dir::advance(error_code*, directory_options)): Return false on
        error.
        (directory_iterator(const path&, directory_options, error_code*)):
        Create end iterator on error (LWG 2723).
        (recursive_directory_iterator(const path&, directory_options,
        error_code*)): Likewise.
        (recursive_directory_iterator::increment): Reset state on error.
        (recursive_directory_iterator::pop): Define new overload.
        * src/filesystem/ops.cc (canonical): Set error for non-existent path.
        (file_time): Take error_code parameter and check for overflow.
        (close_fd): Remove.
        (do_copy_file): Report an error if source or destination is not a
        regular file (LWG 2712). Pass error_code in file_time calls.  Just
        use close(3) instead of close_fd, to prevent retrying on error.
        Check if _GLIBCXX_USE_FCHMODAT is defined.
        [_GLIBCXX_USE_SENDFILE]: Fallback to read/write operations in case
        sendfile fails with ENOSYS or EINVAL. Pass non-null pointer to
        sendfile for offset argument.
        (copy): Update comment to refer to LWG 2681. Implement 2682 and 2683
        resolutions.
        (equivalent): Fix error handling and result when only one file exists.
        (is_empty): Fix error handling.
        (last_write_time(const path&, error_code&)): Pass error_code in
        file_time calls.
        (last_write_time(const path&, file_time_type, error_code&)): Handle
        negative times correctly.
        (permissions(const path&, perms, error_code&)): Handle
        symlink_nofollow.
        (read_symlink): Add missing ec.clear().
        (status(const path&, error_code&)): Handle EOVERFLOW.
        (temp_directory_path): Pass error_code argument to other filesystem
        operations.
        * testsuite/experimental/filesystem/iterators/directory_iterator.cc:
        Update expected behaviour on error.
        * testsuite/experimental/filesystem/iterators/pop.cc: New.
        * testsuite/experimental/filesystem/iterators/
        recursive_directory_iterator.cc: Update expected behaviour on error.
        * testsuite/experimental/filesystem/operations/copy.cc: Update
        expected behaviour for copying directories with create_symlinks.
        Verify that error_code arguments are cleared if there's no error.
        Remove files created by tests. Test copying directories.
        * testsuite/experimental/filesystem/operations/copy_file.cc: Remove
        files created by tests.
        * testsuite/experimental/filesystem/operations/create_symlink.cc: New.
        * testsuite/experimental/filesystem/operations/equivalent.cc: New.
        * testsuite/experimental/filesystem/operations/exists.cc: Test
        overload taking an error_code.
        * testsuite/experimental/filesystem/operations/is_empty.cc: New.
        * testsuite/experimental/filesystem/operations/last_write_time.cc:
        New.
        * testsuite/experimental/filesystem/operations/permissions.cc: Test
        overload taking error_code. Test symlink_nofollow on non-symlinks.
        * testsuite/experimental/filesystem/operations/read_symlink.cc: New.
        * testsuite/experimental/filesystem/operations/remove_all.cc: New.
        * testsuite/experimental/filesystem/operations/temp_directory_path.cc:
        Add testcase for inaccessible directory.
        * testsuite/experimental/filesystem/path/construct/range.cc: Test
        construction from input iterators with const value types.
        * testsuite/experimental/filesystem/path/construct/string_view.cc:
        New.
        * testsuite/util/testsuite_fs.h (scoped_file): Define RAII helper.

diff --git a/libstdc++-v3/include/experimental/bits/fs_dir.h 
b/libstdc++-v3/include/experimental/bits/fs_dir.h
index 70a95eb..818e7ff 100644
--- a/libstdc++-v3/include/experimental/bits/fs_dir.h
+++ b/libstdc++-v3/include/experimental/bits/fs_dir.h
@@ -312,6 +312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     }
 
     void pop();
+    void pop(error_code&);
 
     void disable_recursion_pending() { _M_pending = false; }
 
diff --git a/libstdc++-v3/include/experimental/bits/fs_fwd.h 
b/libstdc++-v3/include/experimental/bits/fs_fwd.h
index e7f2eb0..45cd0ce 100644
--- a/libstdc++-v3/include/experimental/bits/fs_fwd.h
+++ b/libstdc++-v3/include/experimental/bits/fs_fwd.h
@@ -162,7 +162,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
       unknown          =  0xFFFF,
       add_perms                = 0x10000,
       remove_perms     = 0x20000,
-      resolve_symlinks = 0x40000
+      symlink_nofollow = 0x40000
   };
 
   constexpr perms
diff --git a/libstdc++-v3/include/experimental/bits/fs_ops.h 
b/libstdc++-v3/include/experimental/bits/fs_ops.h
index 8506b09..62a9826 100644
--- a/libstdc++-v3/include/experimental/bits/fs_ops.h
+++ b/libstdc++-v3/include/experimental/bits/fs_ops.h
@@ -112,6 +112,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   void current_path(const path& __p);
   void current_path(const path& __p, error_code& __ec) noexcept;
 
+  bool
+  equivalent(const path& __p1, const path& __p2);
+
+  bool
+  equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept;
+
   inline bool
   exists(file_status __s) noexcept
   { return status_known(__s) && __s.type() != file_type::not_found; }
@@ -122,13 +128,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   inline bool
   exists(const path& __p, error_code& __ec) noexcept
-  { return exists(status(__p, __ec)); }
-
-  bool
-  equivalent(const path& __p1, const path& __p2);
-
-  bool
-  equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept;
+  {
+    auto __s = status(__p, __ec);
+    if (status_known(__s))
+      __ec.clear();
+    return exists(__s);
+  }
 
   uintmax_t file_size(const path& __p);
   uintmax_t file_size(const path& __p, error_code& __ec) noexcept;
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h 
b/libstdc++-v3/include/experimental/bits/fs_path.h
index dab8ef0..153d345 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -44,6 +44,9 @@
 #include <bits/stl_algobase.h>
 #include <bits/quoted_string.h>
 #include <bits/locale_conv.h>
+#if __cplusplus >= 201402L
+# include <experimental/string_view>
+#endif
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
@@ -61,6 +64,12 @@ inline namespace v1
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
+#if __cplusplus >= 201402L
+  template<typename _CharT, typename _Traits = std::char_traits<_CharT>>
+    using __basic_string_view
+      = std::experimental::basic_string_view<_CharT, _Traits>;
+#endif
+
   /**
    * @ingroup filesystem
    * @{
@@ -87,6 +96,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static __is_encoded_char<_CharT>
       __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
 
+#if __cplusplus >= 201402L
+    template<typename _CharT, typename _Traits>
+      static __is_encoded_char<_CharT>
+      __is_path_src(const __basic_string_view<_CharT, _Traits>&, int);
+#endif
+
     template<typename _Unknown>
       static std::false_type
       __is_path_src(const _Unknown&, ...);
@@ -130,6 +145,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
       { return __str.data() + __str.size(); }
 
+#if __cplusplus >= 201402L
+    template<typename _CharT, typename _Traits>
+      static const _CharT*
+      _S_range_begin(const __basic_string_view<_CharT, _Traits>& __str)
+      { return __str.data(); }
+
+    template<typename _CharT, typename _Traits>
+      static const _CharT*
+      _S_range_end(const __basic_string_view<_CharT, _Traits>& __str)
+      { return __str.data() + __str.size(); }
+#endif
+
     template<typename _Tp,
             typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
             typename _Val = typename std::iterator_traits<_Iter>::value_type>
@@ -159,6 +186,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       __p.clear();
     }
 
+    path(string_type&& __source)
+    : _M_pathname(std::move(__source))
+    { _M_split_cmpts(); }
+
     template<typename _Source,
             typename _Require = _Path<_Source>>
       path(_Source const& __source)
@@ -193,6 +224,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
     path& operator=(const path& __p) = default;
     path& operator=(path&& __p) noexcept;
+    path& operator=(string_type&& __source);
+    path& assign(string_type&& __source);
 
     template<typename _Source>
       _Path<_Source>&
@@ -237,6 +270,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     path& operator+=(const string_type& __x);
     path& operator+=(const value_type* __x);
     path& operator+=(value_type __x);
+#if __cplusplus >= 201402L
+    path& operator+=(__basic_string_view<value_type> __x);
+#endif
 
     template<typename _Source>
       _Path<_Source>&
@@ -305,6 +341,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     int compare(const path& __p) const noexcept;
     int compare(const string_type& __s) const;
     int compare(const value_type* __s) const;
+#if __cplusplus >= 201402L
+    int compare(const __basic_string_view<value_type> __s) const;
+#endif
 
     // decomposition
 
@@ -379,7 +418,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _S_convert(_Iter __first, _Iter __last)
       {
        using __value_type = typename std::iterator_traits<_Iter>::value_type;
-       return _Cvt<__value_type>::_S_convert(__first, __last);
+       return _Cvt<typename remove_cv<__value_type>::type>::
+         _S_convert(__first, __last);
       }
 
     template<typename _InputIterator>
@@ -387,10 +427,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _S_convert(_InputIterator __src, __null_terminated)
       {
        using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
-       std::basic_string<_Tp> __tmp;
-       while (*__src != _Tp{})
-         __tmp.push_back(*__src++);
-       return _S_convert(__tmp.data(), __tmp.data() + __tmp.size());
+       std::basic_string<typename remove_cv<_Tp>::type> __tmp;
+       for (; *__src != _Tp{}; ++__src)
+         __tmp.push_back(*__src);
+       return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
       }
 
     static string_type
@@ -565,6 +605,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     struct path::__is_encoded_char<char32_t> : std::true_type
     { using value_type = char32_t; };
 
+  template<typename _Tp>
+    struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+
   struct path::_Cmpt : path
   {
     _Cmpt(string_type __s, _Type __t, size_t __pos)
@@ -722,6 +765,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   }
 
   inline path&
+  path::operator=(string_type&& __source)
+  { return *this = path(std::move(__source)); }
+
+  inline path&
+  path::assign(string_type&& __source)
+  { return *this = path(std::move(__source)); }
+
+  inline path&
   path::operator+=(const path& __p)
   {
     return operator+=(__p.native());
@@ -751,6 +802,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return *this;
   }
 
+#if __cplusplus >= 201402L
+  inline path&
+  path::operator+=(__basic_string_view<value_type> __x)
+  {
+    _M_pathname.append(__x.data(), __x.size());
+    _M_split_cmpts();
+    return *this;
+  }
+#endif
+
   template<typename _CharT>
     inline path::_Path<_CharT*, _CharT*>&
     path::operator+=(_CharT __x)
@@ -892,6 +953,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   inline int
   path::compare(const value_type* __s) const { return compare(path(__s)); }
 
+#if __cplusplus >= 201402L
+  inline int
+  path::compare(__basic_string_view<value_type> __s) const
+  { return compare(path(__s)); }
+#endif
+
   inline path
   path::filename() const { return empty() ? path() : *--end(); }
 
diff --git a/libstdc++-v3/src/filesystem/dir.cc 
b/libstdc++-v3/src/filesystem/dir.cc
index 6ff12d0..9a63c4a 100644
--- a/libstdc++-v3/src/filesystem/dir.cc
+++ b/libstdc++-v3/src/filesystem/dir.cc
@@ -79,8 +79,7 @@ namespace
       return (obj & bits) != Bitmask::none;
     }
 
-  // Returns {dirp, p} on success, {nullptr, p} on error.
-  // If an ignored EACCES error occurs returns {}.
+  // Returns {dirp, p} on success, {} on error (whether ignored or not).
   inline fs::_Dir
   open_dir(const fs::path& p, fs::directory_options options,
           std::error_code* ec)
@@ -102,7 +101,7 @@ namespace
             std::error_code(err, std::generic_category())));
 
     ec->assign(err, std::generic_category());
-    return {nullptr, p};
+    return {};
   }
 
   inline fs::file_type
@@ -169,7 +168,7 @@ fs::_Dir::advance(error_code* ec, directory_options options)
              "directory iterator cannot advance",
              std::error_code(err, std::generic_category())));
       ec->assign(err, std::generic_category());
-      return true;
+      return false;
     }
   else
     {
@@ -191,12 +190,6 @@ directory_iterator(const path& p, directory_options 
options, error_code* ec)
       if (sp->advance(ec, options))
        _M_dir.swap(sp);
     }
-  else if (!dir.path.empty())
-    {
-      // An error occurred, we need a non-empty shared_ptr so that *this will
-      // not compare equal to the end iterator.
-      _M_dir.reset(static_cast<fs::_Dir*>(nullptr));
-    }
 }
 
 const fs::directory_entry&
@@ -270,10 +263,6 @@ recursive_directory_iterator(const path& p, 
directory_options options,
              std::error_code(err, std::generic_category())));
 
       ec->assign(err, std::generic_category());
-
-      // An error occurred, we need a non-empty shared_ptr so that *this will
-      // not compare equal to the end iterator.
-      _M_dirs.reset(static_cast<_Dir_stack*>(nullptr));
     }
 }
 
@@ -354,7 +343,10 @@ fs::recursive_directory_iterator::increment(error_code& 
ec) noexcept
     {
       _Dir dir = open_dir(top.entry.path(), _M_options, &ec);
       if (ec)
-       return *this;
+       {
+         _M_dirs.reset();
+         return *this;
+       }
       if (dir.dirp)
          _M_dirs->push(std::move(dir));
     }
@@ -372,19 +364,33 @@ fs::recursive_directory_iterator::increment(error_code& 
ec) noexcept
 }
 
 void
-fs::recursive_directory_iterator::pop()
+fs::recursive_directory_iterator::pop(error_code& ec)
 {
   if (!_M_dirs)
-    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
-         "cannot pop non-dereferenceable recursive directory iterator",
-         std::make_error_code(errc::invalid_argument)));
+    {
+      ec = std::make_error_code(errc::invalid_argument);
+      return;
+    }
 
   do {
     _M_dirs->pop();
     if (_M_dirs->empty())
       {
        _M_dirs.reset();
+       ec.clear();
        return;
       }
-  } while (!_M_dirs->top().advance(nullptr, _M_options));
+  } while (!_M_dirs->top().advance(&ec, _M_options));
+}
+
+void
+fs::recursive_directory_iterator::pop()
+{
+  error_code ec;
+  pop(ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
+         ? "recursive directory iterator cannot pop"
+         : "non-dereferenceable recursive directory iterator cannot pop",
+         ec));
 }
diff --git a/libstdc++-v3/src/filesystem/ops.cc 
b/libstdc++-v3/src/filesystem/ops.cc
index 9fb5b639..0dcb1b4 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -28,7 +28,9 @@
 
 #include <experimental/filesystem>
 #include <functional>
+#include <ostream>
 #include <stack>
+#include <ext/stdio_filebuf.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
@@ -48,9 +50,6 @@
 #endif
 #ifdef _GLIBCXX_USE_SENDFILE
 # include <sys/sendfile.h>
-#else
-# include <ext/stdio_filebuf.h>
-# include <ostream>
 #endif
 #if _GLIBCXX_HAVE_UTIME_H
 # include <utime.h>
@@ -143,7 +142,11 @@ fs::canonical(const path& p, const path& base, error_code& 
ec)
 #endif
 
   if (!exists(pa, ec))
-    return result;
+    {
+      if (!ec)
+       ec = make_error_code(std::errc::no_such_file_or_directory);
+      return result;
+    }
   // else: we know there are (currently) no unresolvable symlink loops
 
   result = pa.root_path();
@@ -289,27 +292,24 @@ namespace
   }
 
   inline fs::file_time_type
-  file_time(const stat_type& st) noexcept
+  file_time(const stat_type& st, std::error_code& ec) noexcept
   {
     using namespace std::chrono;
-    return fs::file_time_type{
 #ifdef _GLIBCXX_USE_ST_MTIM
-       seconds{st.st_mtim.tv_sec} + nanoseconds{st.st_mtim.tv_nsec}
+    time_t s = st.st_mtim.tv_sec;
+    nanoseconds ns{st.st_mtim.tv_nsec};
 #else
-       seconds{st.st_mtime}
+    time_t s = st.st_mtime;
+    nanoseconds ns{};
 #endif
-    };
-  }
 
-  // Returns true if the file descriptor was successfully closed,
-  // otherwise returns false and the reason will be in errno.
-  inline bool
-  close_fd(int fd)
-  {
-    while (::close(fd))
-      if (errno != EINTR)
-       return false;
-    return true;
+    if (s >= (nanoseconds::max().count() / 1e9))
+      {
+       ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
+       return fs::file_time_type::min();
+      }
+    ec.clear();
+    return fs::file_time_type{seconds{s} + ns};
   }
 
   bool
@@ -354,13 +354,25 @@ namespace
          from_st = &st2;
       }
     f = make_file_status(*from_st);
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 2712. copy_file() has a number of unspecified error conditions
+    if (!is_regular_file(f))
+      {
+       ec = std::make_error_code(std::errc::not_supported);
+       return false;
+      }
 
     using opts = fs::copy_options;
 
     if (exists(t))
       {
-       if (!is_other(t) && !is_other(f)
-           && to_st->st_dev == from_st->st_dev
+       if (!is_regular_file(t))
+         {
+           ec = std::make_error_code(std::errc::not_supported);
+           return false;
+         }
+
+       if (to_st->st_dev == from_st->st_dev
            && to_st->st_ino == from_st->st_ino)
          {
            ec = std::make_error_code(std::errc::file_exists);
@@ -374,22 +386,27 @@ namespace
          }
        else if (is_set(option, opts::update_existing))
          {
-           if (file_time(*from_st) <= file_time(*to_st))
-             {
-               ec.clear();
-               return false;
-             }
+           const auto from_mtime = file_time(*from_st, ec);
+           if (ec)
+             return false;
+           if ((from_mtime <= file_time(*to_st, ec)) || ec)
+             return false;
          }
        else if (!is_set(option, opts::overwrite_existing))
          {
            ec = std::make_error_code(std::errc::file_exists);
            return false;
          }
+       else if (!is_regular_file(t))
+         {
+           ec = std::make_error_code(std::errc::not_supported);
+           return false;
+         }
       }
 
     struct CloseFD {
-      ~CloseFD() { if (fd != -1) close_fd(fd); }
-      bool close() { return close_fd(std::exchange(fd, -1)); }
+      ~CloseFD() { if (fd != -1) ::close(fd); }
+      bool close() { return ::close(std::exchange(fd, -1)) == 0; }
       int fd;
     };
 
@@ -416,7 +433,7 @@ namespace
 
 #ifdef _GLIBCXX_USE_FCHMOD
     if (::fchmod(out.fd, from_st->st_mode))
-#elif _GLIBCXX_USE_FCHMODAT
+#elif defined _GLIBCXX_USE_FCHMODAT
     if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
 #else
     if (::chmod(to.c_str(), from_st->st_mode))
@@ -427,7 +444,33 @@ namespace
       }
 
 #ifdef _GLIBCXX_USE_SENDFILE
-    const auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size);
+    off_t offset = 0;
+    const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
+    if (n < 0 && (errno == ENOSYS || errno == EINVAL))
+      {
+#endif
+       __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
+       __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
+       if (sbin.is_open())
+         in.fd = -1;
+       if (sbout.is_open())
+         out.fd = -1;
+       if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
+         {
+           ec = std::make_error_code(std::errc::io_error);
+           return false;
+         }
+       if (!sbout.close() || !sbin.close())
+         {
+           ec.assign(errno, std::generic_category());
+           return false;
+         }
+
+       ec.clear();
+       return true;
+
+#ifdef _GLIBCXX_USE_SENDFILE
+      }
     if (n != from_st->st_size)
       {
        ec.assign(errno, std::generic_category());
@@ -438,27 +481,10 @@ namespace
        ec.assign(errno, std::generic_category());
        return false;
       }
-#else
-    __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
-    __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
-    if (sbin.is_open())
-      in.fd = -1;
-    if (sbout.is_open())
-      out.fd = -1;
-    if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
-      {
-       ec = std::make_error_code(std::errc::io_error);
-       return false;
-      }
-    if (!sbout.close() || !sbin.close())
-      {
-       ec.assign(errno, std::generic_category());
-       return false;
-      }
-#endif
 
     ec.clear();
     return true;
+#endif
   }
 }
 #endif
@@ -474,7 +500,8 @@ fs::copy(const path& from, const path& to, copy_options 
options,
 
   file_status f, t;
   stat_type from_st, to_st;
-  // N4099 doesn't check copy_symlinks here, but I think that's a defect.
+  // _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))
@@ -541,6 +568,10 @@ fs::copy(const path& from, const path& to, copy_options 
options,
          do_copy_file(from, to, options, &from_st, ptr,  ec);
        }
     }
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2682. filesystem::copy() won't create a symlink to a directory
+  else if (is_directory(f) && create_symlinks)
+    ec = std::make_error_code(errc::is_a_directory);
   else if (is_directory(f) && (is_set(options, copy_options::recursive)
                               || options == copy_options::none))
     {
@@ -553,7 +584,10 @@ fs::copy(const path& from, const path& to, copy_options 
options,
       for (const directory_entry& x : directory_iterator(from))
        copy(x.path(), to/x.path().filename(), options, ec);
     }
-  // "Otherwise no effects." (should ec.clear() be called?)
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2683. filesystem::copy() says "no effects"
+  else
+    ec.clear();
 }
 
 bool
@@ -890,7 +924,7 @@ fs::equivalent(const path& p1, const path& p2)
 {
   error_code ec;
   auto result = equivalent(p1, p2, ec);
-  if (ec.value())
+  if (ec)
     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
          p1, p2, ec));
   return result;
@@ -900,25 +934,42 @@ bool
 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
 {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  int err = 0;
+  file_status s1, s2;
   stat_type st1, st2;
-  if (::stat(p1.c_str(), &st1) == 0 && ::stat(p2.c_str(), &st2) == 0)
+  if (::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)
+    s2 = make_file_status(st2);
+  else if (is_not_found_errno(errno))
+    s2.type(file_type::not_found);
+  else
+    err = errno;
+
+  if (exists(s1) && exists(s2))
     {
-      file_status s1 = make_file_status(st1);
-      file_status s2 = make_file_status(st2);
       if (is_other(s1) && is_other(s2))
        {
          ec = std::make_error_code(std::errc::not_supported);
          return false;
        }
       ec.clear();
+      if (is_other(s1) || is_other(s2))
+       return false;
       return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
     }
-  else if (is_not_found_errno(errno))
-    {
-      ec = std::make_error_code(std::errc::no_such_file_or_directory);
-      return false;
-    }
-  ec.assign(errno, std::generic_category());
+  else if (!exists(s1) && !exists(s2))
+    ec = std::make_error_code(std::errc::no_such_file_or_directory);
+  else if (err)
+    ec.assign(err, std::generic_category());
+  else
+    ec.clear();
+  return false;
 #else
   ec = std::make_error_code(std::errc::not_supported);
 #endif
@@ -1000,20 +1051,24 @@ fs::hard_link_count(const path& p, error_code& ec) 
noexcept
 bool
 fs::is_empty(const path& p)
 {
-  return fs::is_directory(status(p))
-    ? fs::directory_iterator(p) == fs::directory_iterator()
-    : fs::file_size(p) == 0;
+  error_code ec;
+  bool e = is_empty(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
+                                            p, ec));
+  return e;
 }
 
 bool
 fs::is_empty(const path& p, error_code& ec) noexcept
 {
   auto s = status(p, ec);
-  if (ec.value())
+  if (ec)
     return false;
-  return fs::is_directory(s)
+  bool empty = fs::is_directory(s)
     ? fs::directory_iterator(p, ec) == fs::directory_iterator()
     : fs::file_size(p, ec) == 0;
+  return ec ? false : empty;
 }
 
 fs::file_time_type
@@ -1029,7 +1084,7 @@ fs::last_write_time(const path& p)
 fs::file_time_type
 fs::last_write_time(const path& p, error_code& ec) noexcept
 {
-  return do_stat(p, ec, [](const auto& st) { return file_time(st); },
+  return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
                 file_time_type::min());
 }
 
@@ -1050,6 +1105,11 @@ fs::last_write_time(const path& p 
__attribute__((__unused__)),
   auto s = chrono::duration_cast<chrono::seconds>(d);
 #if _GLIBCXX_USE_UTIMENSAT
   auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
+  if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
+    {
+      --s;
+      ns += chrono::seconds(1);
+    }
   struct ::timespec ts[2];
   ts[0].tv_sec = 0;
   ts[0].tv_nsec = UTIME_OMIT;
@@ -1082,10 +1142,12 @@ fs::permissions(const path& p, perms prms)
     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
 }
 
-void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
+void
+fs::permissions(const path& p, perms prms, error_code& ec) noexcept
 {
   const bool add = is_set(prms, perms::add_perms);
   const bool remove = is_set(prms, perms::remove_perms);
+  const bool nofollow = is_set(prms, perms::symlink_nofollow);
   if (add && remove)
     {
       ec = std::make_error_code(std::errc::invalid_argument);
@@ -1094,24 +1156,33 @@ void fs::permissions(const path& p, perms prms, 
error_code& ec) noexcept
 
   prms &= perms::mask;
 
-  if (add || remove)
+  file_status st;
+  if (add || remove || nofollow)
     {
-      auto st = status(p, ec);
+      st = nofollow ? symlink_status(p, ec) : status(p, ec);
       if (ec)
        return;
       auto curr = st.permissions();
       if (add)
        prms |= curr;
-      else
+      else if (remove)
        prms = curr & ~prms;
     }
 
+  int err = 0;
 #if _GLIBCXX_USE_FCHMODAT
-  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0))
+  const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
+  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
+    err = errno;
 #else
-  if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+  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)))
+    err = errno;
 #endif
-    ec.assign(errno, std::generic_category());
+
+  if (err)
+    ec.assign(err, std::generic_category());
   else
     ec.clear();
 }
@@ -1142,6 +1213,7 @@ fs::path fs::read_symlink(const path& p, error_code& ec)
       ec.assign(errno, std::generic_category());
       return {};
     }
+  ec.clear();
   return path{buf.data(), buf.data()+len};
 #else
   ec = std::make_error_code(std::errc::not_supported);
@@ -1282,7 +1354,7 @@ fs::space(const path& p, error_code& ec) noexcept
 
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
 fs::file_status
-fs::status(const fs::path& p, std::error_code& ec) noexcept
+fs::status(const fs::path& p, error_code& ec) noexcept
 {
   file_status status;
   stat_type st;
@@ -1292,6 +1364,10 @@ fs::status(const fs::path& p, std::error_code& ec) 
noexcept
       ec.assign(err, std::generic_category());
       if (is_not_found_errno(err))
        status.type(file_type::not_found);
+#ifdef EOVERFLOW
+      else if (err == EOVERFLOW)
+       status.type(file_type::unknown);
+#endif
     }
   else
     {
@@ -1390,12 +1466,17 @@ fs::path fs::temp_directory_path(error_code& ec)
   for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
     tmpdir = ::getenv(*e);
   path p = tmpdir ? tmpdir : "/tmp";
-  if (exists(p) && is_directory(p))
+  auto st = status(p, ec);
+  if (!ec)
     {
-      ec.clear();
-      return p;
+      if (is_directory(st))
+       {
+         ec.clear();
+         return p;
+       }
+      else
+       ec = std::make_error_code(std::errc::not_a_directory);
     }
-  ec = std::make_error_code(std::errc::not_a_directory);
   return {};
 #endif
 }
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
 
b/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
index ffd97ce..6b8e3fc 100644
--- 
a/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/iterators/directory_iterator.cc
@@ -34,14 +34,14 @@ test01()
   const auto p = __gnu_test::nonexistent_path();
   fs::directory_iterator iter(p, ec);
   VERIFY( ec );
-  VERIFY( iter != fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test empty directory.
   create_directory(p, fs::current_path(), ec);
   VERIFY( !ec );
   iter = fs::directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter == fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test non-empty directory.
   create_directory_symlink(p, p / "l", ec);
@@ -51,20 +51,20 @@ test01()
   VERIFY( iter != fs::directory_iterator() );
   VERIFY( iter->path() == p/"l" );
   ++iter;
-  VERIFY( iter == fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible directory.
   permissions(p, fs::perms::none, ec);
   VERIFY( !ec );
   iter = fs::directory_iterator(p, ec);
   VERIFY( ec );
-  VERIFY( iter != fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible directory, skipping permission denied.
   const auto opts = fs::directory_options::skip_permission_denied;
   iter = fs::directory_iterator(p, opts, ec);
   VERIFY( !ec );
-  VERIFY( iter == fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   permissions(p, fs::perms::owner_all, ec);
   remove_all(p, ec);
@@ -84,12 +84,12 @@ test02()
   // Test post-increment (libstdc++/71005)
   auto iter = fs::directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter != fs::directory_iterator() );
+  VERIFY( iter != end(iter) );
   const auto entry1 = *iter;
   const auto entry2 = *iter++;
   VERIFY( entry1 == entry2 );
   VERIFY( entry1.path() == p/"l" );
-  VERIFY( iter == fs::directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   remove_all(p, ec);
 }
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/iterators/pop.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/iterators/pop.cc
new file mode 100644
index 0000000..9306c03
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/iterators/pop.cc
@@ -0,0 +1,108 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test01()
+{
+  std::error_code ec;
+  fs::recursive_directory_iterator dir;
+  dir.pop(ec);  // This is undefined, but our implementation
+  VERIFY( ec ); // checks and returns an error.
+  VERIFY( dir == end(dir) );
+
+  std::error_code ec2;
+  try
+  {
+    dir.pop();
+  }
+  catch (const fs::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+  }
+  VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+  std::error_code ec = make_error_code(std::errc::interrupted);
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "d1/d2/d3");
+  for (int i = 0; i < 3; ++i)
+  {
+    fs::recursive_directory_iterator dir(p);
+    std::advance(dir, i);
+    VERIFY( dir.depth() == i );
+    dir.pop(ec);
+    VERIFY( !ec );
+    VERIFY( dir == end(dir) );
+
+    dir = fs::recursive_directory_iterator(p);
+    std::advance(dir, i);
+    VERIFY( dir.depth() == i );
+    dir.pop();
+    VERIFY( dir == end(dir) );
+  }
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  std::error_code ec = make_error_code(std::errc::interrupted);
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "d1/d2/d3");
+  create_directories(p / "d1/d2/e3");
+  create_directories(p / "d1/e2/d3");
+  for (int i = 0; i < 3; ++i)
+  {
+    fs::recursive_directory_iterator dir(p);
+    std::advance(dir, i);
+    int expected_depth = i;
+    VERIFY( dir.depth() == expected_depth );
+    dir.pop(ec);
+    VERIFY( !ec );
+    if (dir != end(dir))
+      VERIFY( dir.depth() == (expected_depth - 1) );
+
+    dir = fs::recursive_directory_iterator(p);
+    std::advance(dir, i);
+    VERIFY( dir.depth() == i );
+    dir.pop();
+    if (dir != end(dir))
+      VERIFY( dir.depth() == (i -1) );
+  }
+  remove_all(p, ec);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
 
b/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
index b44ff3f..9e94c47 100644
--- 
a/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
@@ -34,39 +34,39 @@ test01()
   const auto p = __gnu_test::nonexistent_path();
   fs::recursive_directory_iterator iter(p, ec);
   VERIFY( ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test empty directory.
   create_directory(p, fs::current_path(), ec);
   VERIFY( !ec );
   iter = fs::recursive_directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter == fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test non-empty directory.
   create_directories(p / "d1/d2");
   VERIFY( !ec );
   iter = fs::recursive_directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter != end(iter) );
   VERIFY( iter->path() == p/"d1" );
   ++iter;
   VERIFY( iter->path() == p/"d1/d2" );
   ++iter;
-  VERIFY( iter == fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible directory.
   permissions(p, fs::perms::none, ec);
   VERIFY( !ec );
   iter = fs::recursive_directory_iterator(p, ec);
   VERIFY( ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible directory, skipping permission denied.
   const auto opts = fs::directory_options::skip_permission_denied;
   iter = fs::recursive_directory_iterator(p, opts, ec);
   VERIFY( !ec );
-  VERIFY( iter == fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible sub-directory.
   permissions(p, fs::perms::owner_all, ec);
@@ -75,23 +75,24 @@ test01()
   VERIFY( !ec );
   iter = fs::recursive_directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter != end(iter) );
   VERIFY( iter->path() == p/"d1" );
   ++iter;              // should recurse into d1
   VERIFY( iter->path() == p/"d1/d2" );
   iter.increment(ec);  // should fail to recurse into p/d1/d2
   VERIFY( ec );
+  VERIFY( iter == end(iter) );
 
   // Test inaccessible sub-directory, skipping permission denied.
   iter = fs::recursive_directory_iterator(p, opts, ec);
   VERIFY( !ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter != end(iter) );
   VERIFY( iter->path() == p/"d1" );
   ++iter;              // should recurse into d1
   VERIFY( iter->path() == p/"d1/d2" );
   iter.increment(ec);  // should fail to recurse into p/d1/d2, so skip it
   VERIFY( !ec );
-  VERIFY( iter == fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   permissions(p/"d1/d2", fs::perms::owner_all, ec);
   remove_all(p, ec);
@@ -110,7 +111,7 @@ test02()
   // Test post-increment (libstdc++/71005)
   auto iter = fs::recursive_directory_iterator(p, ec);
   VERIFY( !ec );
-  VERIFY( iter != fs::recursive_directory_iterator() );
+  VERIFY( iter != end(iter) );
   const auto entry1 = *iter;
   const auto entry2 = *iter++;
   VERIFY( entry1 == entry2 );
@@ -119,7 +120,7 @@ test02()
   const auto entry4 = *iter++;
   VERIFY( entry3 == entry4 );
   VERIFY( entry3.path() == p/"d1/d2" );
-  VERIFY( iter == fs::recursive_directory_iterator() );
+  VERIFY( iter == end(iter) );
 
   remove_all(p, ec);
 }
@@ -150,7 +151,7 @@ test04()
 
   // libstdc++/71004
   const fs::recursive_directory_iterator it;
-  VERIFY( it == fs::recursive_directory_iterator() );
+  VERIFY( it == end(it) );
 }
 
 void
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
index a5f6a3e..e53e75a 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
@@ -21,7 +21,6 @@
 // 15.3 Copy [fs.op.copy]
 
 #include <experimental/filesystem>
-#include <fstream>
 #include <testsuite_fs.h>
 #include <testsuite_hooks.h>
 
@@ -44,14 +43,25 @@ test01()
   fs::copy(".", ".", fs::copy_options::none, ec);
   VERIFY( ec );
 
-  std::ofstream{p.native()};
+  __gnu_test::scoped_file f(p);
   VERIFY( fs::is_directory(".") );
   VERIFY( fs::is_regular_file(p) );
   ec.clear();
   fs::copy(".", p, fs::copy_options::none, ec);
   VERIFY( ec );
 
-  remove(p, ec);
+  auto to = __gnu_test::nonexistent_path();
+  ec.clear();
+  auto opts = fs::copy_options::create_symlinks;
+  fs::copy("/", to, opts, ec);
+  VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+  VERIFY( !exists(to) );
+
+  ec.clear();
+  opts != fs::copy_options::recursive;
+  fs::copy("/", to, opts, ec);
+  VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+  VERIFY( !exists(to) );
 }
 
 // Test is_symlink(f) case.
@@ -62,29 +72,35 @@ test02()
 
   auto from = __gnu_test::nonexistent_path();
   auto to = __gnu_test::nonexistent_path();
-  std::error_code ec;
+  std::error_code ec, bad = std::make_error_code(std::errc::invalid_argument);
 
+  ec = bad;
   fs::create_symlink(".", from, ec);
   VERIFY( !ec );
   VERIFY( fs::exists(from) );
 
+  ec = bad;
   fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
   VERIFY( !ec );
   VERIFY( !fs::exists(to) );
 
+  ec = bad;
   fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
   VERIFY( !ec );
   VERIFY( !fs::exists(to) );
 
+  ec = bad;
   fs::copy(from, to,
            fs::copy_options::skip_symlinks|fs::copy_options::copy_symlinks,
            ec);
   VERIFY( !ec );
   VERIFY( !fs::exists(to) );
 
+  ec = bad;
   fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
   VERIFY( !ec );
   VERIFY( fs::exists(to) );
+  VERIFY( is_symlink(to) );
 
   fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
   VERIFY( ec );
@@ -117,6 +133,9 @@ test03()
   fs::copy(from, to);
   VERIFY( fs::exists(to) );
   VERIFY( fs::file_size(to) == fs::file_size(from) );
+
+  remove(from);
+  remove(to);
 }
 
 // Test is_directory(f) case.
@@ -129,6 +148,37 @@ test04()
   auto to = __gnu_test::nonexistent_path();
   std::error_code ec;
 
+  create_directories(from/"a/b/c");
+
+  {
+    __gnu_test::scoped_file f(to);
+    copy(from, to, ec);
+    VERIFY( ec );
+  }
+
+  __gnu_test::scoped_file f1(from/"a/f1");
+  std::ofstream{f1.path} << "file one";
+  __gnu_test::scoped_file f2(from/"a/b/f2");
+  std::ofstream{f2.path} << "file two";
+
+  copy(from, to, ec);
+  VERIFY( !ec );
+  VERIFY( exists(to) && is_empty(to) );
+  remove(to);
+
+  copy(from, to, fs::copy_options::recursive, ec);
+  VERIFY( !ec );
+  VERIFY( exists(to) && !is_empty(to) );
+  VERIFY( is_regular_file(to/"a/f1") && !is_empty(to/"a/f1") );
+  VERIFY( file_size(from/"a/f1") == file_size(to/"a/f1") );
+  VERIFY( is_regular_file(to/"a/b/f2") && !is_empty(to/"a/b/f2") );
+  VERIFY( file_size(from/"a/b/f2") == file_size(to/"a/b/f2") );
+  VERIFY( is_directory(to/"a/b/c") && is_empty(to/"a/b/c") );
+
+  f1.path.clear();
+  f2.path.clear();
+  remove_all(from, ec);
+  remove_all(to, ec);
 }
 
 // Test no-op cases.
@@ -138,10 +188,10 @@ test05()
   bool test __attribute__((unused)) = false;
 
   auto to = __gnu_test::nonexistent_path();
-  std::error_code ec;
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
 
-  fs::copy("/", to, fs::copy_options::create_symlinks, ec);
-  VERIFY( !ec );
+  fs::copy("/", to, fs::copy_options::copy_symlinks, ec);
+  VERIFY( !ec );  // Previous value should be cleared (LWG 2683)
 }
 
 int
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
index cdb7911..bcbdd12 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy_file.cc
@@ -73,6 +73,9 @@ test01()
   VERIFY( !ec );
   VERIFY( exists(to) );
   VERIFY( file_size(to) == file_size(from) );
+
+  remove(from);
+  remove(to);
 }
 
 int
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc
new file mode 100644
index 0000000..7297259
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc
@@ -0,0 +1,93 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test01()
+{
+  std::error_code ec, ec2;
+  __gnu_test::scoped_file f;
+  auto tgt = f.path;
+
+  // Test empty path.
+  fs::path p;
+  create_symlink(tgt, p, ec );
+  VERIFY( ec );
+  try
+  {
+    create_symlink(tgt, p);
+  }
+  catch (const std::experimental::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == tgt );
+    VERIFY( ex.path2() == p );
+  }
+  VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+  std::error_code ec, ec2;
+  __gnu_test::scoped_file f;
+  auto tgt = f.path;
+
+  // Test non-existent path
+  auto p = __gnu_test::nonexistent_path();
+  VERIFY( !exists(p) );
+
+  create_symlink(tgt, p, ec); // create the symlink once
+  VERIFY( !ec );
+  VERIFY( exists(p) );
+  VERIFY( is_symlink(p) );
+  remove(p);
+  create_symlink(tgt, p); // create the symlink again
+  VERIFY( exists(p) );
+  VERIFY( is_symlink(p) );
+
+  create_symlink(tgt, p, ec); // Try to create existing symlink
+  VERIFY( ec );
+  try
+  {
+    create_symlink(tgt, p);
+  }
+  catch (const std::experimental::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == tgt );
+    VERIFY( ex.path2() == p );
+  }
+  VERIFY( ec2 == ec );
+
+  remove(p);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/equivalent.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/equivalent.cc
new file mode 100644
index 0000000..77ed054
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/equivalent.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::experimental::filesystem;
+
+
+void
+test01()
+{
+  auto p1 = __gnu_test::nonexistent_path();
+  auto p2 = __gnu_test::nonexistent_path();
+  std::error_code ec;
+  bool result;
+
+  result = equivalent(p1, p2, ec);
+  VERIFY( ec );
+  VERIFY( !result );
+  const auto bad_ec = ec;
+
+  __gnu_test::scoped_file f1(p1);
+  result = equivalent(p1, p2, ec);
+  VERIFY( !ec );
+  VERIFY( !result );
+
+  __gnu_test::scoped_file f2(p2);
+  ec = bad_ec;
+  result = equivalent(p1, p2, ec);
+  VERIFY( !ec );
+  VERIFY( !result );
+
+  auto p3 = __gnu_test::nonexistent_path();
+  create_hard_link(p1, p3, ec);
+  if (ec)
+    return;  // hard links not supported
+  __gnu_test::scoped_file f3(p3, __gnu_test::scoped_file::adopt_file);
+
+  ec = bad_ec;
+  result = equivalent(p1, p3, ec);
+  VERIFY( !ec );
+  VERIFY( result );
+
+  ec = bad_ec;
+  result = equivalent(p2, p3, ec);
+  VERIFY( !ec );
+  VERIFY( !result );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
index 633095d..39f45b1 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/exists.cc
@@ -34,6 +34,18 @@ test01()
   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( !ec );
+  VERIFY( exists(path{"/."}, ec) );
+  VERIFY( !ec );
+  VERIFY( exists(path{"."}, ec) );
+  VERIFY( !ec );
+  VERIFY( exists(path{".."}, ec) );
+  VERIFY( !ec );
+  VERIFY( exists(std::experimental::filesystem::current_path(), ec) );
+  VERIFY( !ec );
 }
 
 void
@@ -43,6 +55,10 @@ test02()
 
   path rel = __gnu_test::nonexistent_path();
   VERIFY( !exists(rel) );
+
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+  VERIFY( !exists(rel, ec) );
+  VERIFY( !ec ); // DR 2725
 }
 
 void
@@ -52,6 +68,38 @@ test03()
 
   path abs = absolute(__gnu_test::nonexistent_path());
   VERIFY( !exists(abs) );
+
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+  VERIFY( !exists(abs, ec) );
+  VERIFY( !ec ); // DR 2725
+}
+
+void
+test04()
+{
+  using perms = std::experimental::filesystem::perms;
+  path p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  permissions(p, perms::all | perms::remove_perms);
+
+  auto unr = p / "unreachable";
+  std::error_code ec;
+  VERIFY( !exists(unr, ec) );
+  VERIFY( ec == std::errc::permission_denied );
+  ec.clear();
+  try
+  {
+    exists(unr);
+  }
+  catch(const std::experimental::filesystem::filesystem_error& ex)
+  {
+    ec = ex.code();
+    VERIFY( ex.path1() == unr );
+  }
+  VERIFY( ec == std::errc::permission_denied );
+
+  permissions(p, perms::owner_all);
+  remove(p);
 }
 
 int
@@ -60,4 +108,5 @@ main()
   test01();
   test02();
   test03();
+  test04();
 }
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc
new file mode 100644
index 0000000..d35967a
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/is_empty.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }E
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  permissions(p, fs::perms::none);
+  std::error_code ec, ec2;
+
+  bool result = fs::is_empty(p, ec);
+  VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+  VERIFY( !result );
+
+  try {
+    fs::is_empty(p);
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+
+  result = fs::is_empty(p/"f", ec);
+  VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+  VERIFY( !result );
+
+  try {
+    fs::is_empty(p/"f");
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+
+  permissions(p, fs::perms::owner_all, ec);
+  remove_all(p, ec);
+}
+
+void
+test02()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  std::error_code ec, bad_ec = make_error_code(std::errc::invalid_argument);
+  bool empty;
+
+  ec = bad_ec;
+  empty = is_empty(p, ec);
+  VERIFY( !ec );
+  VERIFY( empty );
+  empty = is_empty(p);
+  VERIFY( empty );
+
+  __gnu_test::scoped_file f(p/"f");
+  ec = bad_ec;
+  empty = is_empty(f.path, ec);
+  VERIFY( !ec );
+  VERIFY( empty );
+  empty = is_empty(f.path);
+  VERIFY( empty );
+
+  std::ofstream{f.path.native()} << "data";
+  ec = bad_ec;
+  empty = is_empty(p, ec);
+  VERIFY( !ec );
+  VERIFY( !empty );
+  empty = is_empty(p);
+  VERIFY( !empty );
+
+  ec = bad_ec;
+  empty = is_empty(p, ec);
+  VERIFY( !ec );
+  VERIFY( !empty );
+  empty = is_empty(p);
+  VERIFY( !empty );
+
+  f.path.clear();
+  remove_all(p, ec);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
new file mode 100644
index 0000000..a60a25f
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/last_write_time.cc
@@ -0,0 +1,156 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+// 15.25 Permissions [fs.op.last_write_time]
+
+#include <experimental/filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+using time_type = std::experimental::filesystem::file_time_type;
+
+void
+test01()
+{
+  // read times
+
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+  time_type mtime = last_write_time(p, ec);
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#if __cpp_exceptions
+  bool caught = false;
+  try {
+    mtime = last_write_time(p);
+  } catch (std::system_error const& e) {
+    caught = true;
+    ec = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#endif
+
+  __gnu_test::scoped_file file(p);
+  VERIFY( exists(p) );
+  mtime = last_write_time(p, ec);
+  VERIFY( !ec );
+  VERIFY( mtime <= time_type::clock::now() );
+  VERIFY( mtime == last_write_time(p) );
+
+  auto end_of_time = time_type::duration::max();
+  auto last_second
+    = std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
+  if (last_second > std::numeric_limits<std::time_t>::max())
+    return; // can't test overflow
+
+#if _GLIBCXX_USE_UTIMENSAT
+  struct ::timespec ts[2];
+  ts[0].tv_sec = 0;
+  ts[0].tv_nsec = UTIME_NOW;
+  ts[1].tv_sec = std::numeric_limits<std::time_t>::max() - 1;
+  ts[1].tv_nsec = 0;
+  VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) );
+#elif _GLIBCXX_HAVE_UTIME_H
+  ::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) );
+#else
+  return;
+#endif
+
+  mtime = last_write_time(p, ec);
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+  VERIFY( mtime == time_type::min() );
+
+#if __cpp_exceptions
+  caught = false;
+  try {
+    mtime = last_write_time(p);
+  } catch (std::system_error const& e) {
+    caught = true;
+    ec = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+#endif
+}
+
+bool approx_equal(time_type file_time, time_type expected)
+{
+  auto delta = expected - file_time;
+  if (delta < delta.zero())
+    delta = -delta;
+  return delta < std::chrono::seconds(1);
+}
+
+void
+test02()
+{
+  // write times
+
+  __gnu_test::scoped_file f;
+  std::error_code ec;
+  time_type time;
+
+  time = last_write_time(f.path);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  time += std::chrono::milliseconds(1000 * 60 * 20 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  time = time_type();
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc
index e414860..45f1142 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc
@@ -21,7 +21,6 @@
 // 15.26 Permissions [fs.op.permissions]
 
 #include <experimental/filesystem>
-#include <fstream>
 #include <testsuite_fs.h>
 #include <testsuite_hooks.h>
 
@@ -32,7 +31,8 @@ test01()
   using perms = std::experimental::filesystem::perms;
 
   auto p = __gnu_test::nonexistent_path();
-  std::ofstream{p.native()};
+
+  __gnu_test::scoped_file f(p);
   VERIFY( exists(p) );
   permissions(p, perms::owner_all);
   VERIFY( status(p).permissions() == perms::owner_all );
@@ -40,12 +40,113 @@ test01()
   VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
   permissions(p, perms::group_read | perms::remove_perms);
   VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test02()
+{
+  using perms = std::experimental::filesystem::perms;
+
+  auto p = __gnu_test::nonexistent_path();
+
+  std::error_code ec;
+  permissions(p, perms::owner_all, ec);
+  VERIFY( ec );
+
+  __gnu_test::scoped_file f(p);
+  VERIFY( exists(p) );
+
+  ec = std::make_error_code(std::errc::invalid_argument);
+  permissions(p, perms::owner_all, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == perms::owner_all );
+  permissions(p, perms::group_read | perms::add_perms, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
+  permissions(p, perms::group_read | perms::remove_perms, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test03()
+{
+  using perms = std::experimental::filesystem::perms;
+
+  __gnu_test::scoped_file f;
+  VERIFY( exists(f.path) );
+
+  auto p = __gnu_test::nonexistent_path();
+  create_symlink(f.path, p);
+
+  std::error_code ec, ec2;
+  permissions(p, perms::owner_all | perms::symlink_nofollow, ec);
+  try
+  {
+    permissions(p, perms::owner_all | perms::symlink_nofollow);
+  }
+  catch (const std::experimental::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == p );
+  }
+  // Both calls should succeed, or both should fail with same error:
+  VERIFY( ec == ec2 );
 
   remove(p);
 }
 
+void
+test04()
+{
+  using perms = std::experimental::filesystem::perms;
+
+  auto p = __gnu_test::nonexistent_path();
+  create_symlink(__gnu_test::nonexistent_path(), p);
+
+  std::error_code ec, ec2;
+  permissions(p, perms::owner_all, ec);
+  VERIFY( ec );
+  try
+  {
+    permissions(p, perms::owner_all);
+  }
+  catch (const std::experimental::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == p );
+  }
+  VERIFY( ec == ec2 );
+
+  remove(p);
+}
+
+void
+test05()
+{
+  using perms = std::experimental::filesystem::perms;
+  std::error_code ec;
+
+  __gnu_test::scoped_file f;
+  auto p = perms::owner_write;
+
+  // symlink_nofollow should not give an error for non-symlinks
+  permissions(f.path, p|perms::symlink_nofollow, ec);
+  VERIFY( !ec );
+  auto st = status(f.path);
+  VERIFY( st.permissions() == p );
+  p |= perms::owner_read;
+  permissions(f.path, p|perms::symlink_nofollow, ec);
+  st = status(f.path);
+  VERIFY( st.permissions() == p );
+}
+
 int
 main()
 {
   test01();
+  test02();
+  test03();
+  test04();
+  test05();
 }
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc
new file mode 100644
index 0000000..c67b318
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+
+  read_symlink(p, ec);
+  VERIFY( ec );
+
+  fs::path tgt = ".";
+  create_symlink(tgt, p);
+
+  auto result = read_symlink(p, ec);
+  VERIFY( !ec );
+  VERIFY( result == tgt );
+
+  remove(p);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/remove_all.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/remove_all.cc
new file mode 100644
index 0000000..57d15af
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/remove_all.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::experimental::filesystem;
+
+void
+test01()
+{
+  std::error_code ec;
+  std::uintmax_t n;
+
+  n = fs::remove_all("", ec);
+  VERIFY( ec );
+  VERIFY( n == std::uintmax_t(-1) );
+
+  auto p = __gnu_test::nonexistent_path();
+  ec.clear();
+  n = remove_all(p, ec);
+  VERIFY( ec );
+  VERIFY( n == std::uintmax_t(-1) );
+
+  const auto bad_ec = ec;
+  auto link = __gnu_test::nonexistent_path();
+  create_symlink(p, link);  // dangling symlink
+  ec = bad_ec;
+  n = remove_all(link, ec);
+  VERIFY( !ec );
+  VERIFY( n == 1 );
+  VERIFY( !exists(symlink_status(link)) ); // DR 2721
+
+  __gnu_test::scoped_file f(p);
+  create_symlink(p, link);
+  ec = bad_ec;
+  n = remove_all(link, ec);
+  VERIFY( !ec );
+  VERIFY( n == 1 );
+  VERIFY( !exists(symlink_status(link)) );  // The symlink is removed, but
+  VERIFY( exists(p) );                      // its target is not.
+
+  auto dir = __gnu_test::nonexistent_path();
+  create_directories(dir/"a/b/c");
+  ec = bad_ec;
+  n = remove_all(dir/"a", ec);
+  VERIFY( !ec );
+  VERIFY( n == 3 );
+  VERIFY( exists(dir) );
+  VERIFY( !exists(dir/"a") );
+
+  create_directories(dir/"a/b/c");
+  __gnu_test::scoped_file a1(dir/"a/1");
+  __gnu_test::scoped_file a2(dir/"a/2");
+  __gnu_test::scoped_file b1(dir/"a/b/1");
+  __gnu_test::scoped_file b2(dir/"a/b/2");
+  ec = bad_ec;
+  n = remove_all(dir, ec);
+  VERIFY( !ec );
+  VERIFY( n == 8 );
+  VERIFY( !exists(dir) );
+
+  a1.path.clear();
+  a2.path.clear();
+  b1.path.clear();
+  b2.path.clear();
+}
+
+int
+main()
+{
+  test01();
+}
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 1ae363b..23d4b9c 100644
--- 
a/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
@@ -46,6 +46,7 @@ test01()
 
   std::error_code ec;
   fs::path p1 = fs::temp_directory_path(ec);
+  VERIFY( !ec );
   VERIFY( exists(p1) );
 
   fs::path p2 = fs::temp_directory_path();
@@ -65,6 +66,7 @@ test02()
   std::error_code ec;
   fs::path p = fs::temp_directory_path(ec);
   VERIFY( ec );
+  VERIFY( p == fs::path() );
 
   std::error_code ec2;
   try {
@@ -75,10 +77,54 @@ test02()
   VERIFY( ec2 == ec );
 }
 
+void
+test03()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directories(p/"tmp");
+  permissions(p, fs::perms::none);
+  setenv("TMPDIR", (p/"tmp").c_str(), 1);
+  std::error_code ec;
+  auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
+  VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+  VERIFY( r == fs::path() );
+
+  std::error_code ec2;
+  try {
+    fs::temp_directory_path();
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+
+  permissions(p, fs::perms::owner_all, ec);
+  remove_all(p, ec);
+}
+
+void
+test04()
+{
+  __gnu_test::scoped_file f;
+  setenv("TMPDIR", f.path.c_str(), 1);
+  std::error_code ec;
+  auto r = fs::temp_directory_path(ec);
+  VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
+  VERIFY( r == fs::path() );
+
+  std::error_code ec2;
+  try {
+    fs::temp_directory_path();
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+}
 
 int
 main()
 {
   test01();
   test02();
+  test03();
+  test04();
 }
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
index 90eaf30..9e51e0a 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
@@ -1,4 +1,5 @@
-// { dg-options "-std=gnu++11 -lstdc++fs" }
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
 // { dg-require-filesystem-ts "" }
 
 // Copyright (C) 2014-2016 Free Software Foundation, Inc.
@@ -23,6 +24,7 @@
 #include <experimental/filesystem>
 #include <string>
 #include <testsuite_fs.h>
+#include <testsuite_iterators.h>
 
 using std::experimental::filesystem::path;
 using __gnu_test::compare_paths;
@@ -53,6 +55,53 @@ test01()
     compare_paths(p1, p7);
     compare_paths(p1, p8);
 #endif
+
+    using __gnu_test::test_container;
+    using __gnu_test::input_iterator_wrapper;
+    // Test with input iterators and const value_types
+
+    test_container<char, input_iterator_wrapper>
+      r1((char*)s.c_str(), (char*)s.c_str() + s.size());
+    path p9(r1.begin(), r1.end());
+    compare_paths(p1, p9);
+
+    test_container<char, input_iterator_wrapper>
+      r2((char*)s.c_str(), (char*)s.c_str() + s.size() + 1); // includes 
null-terminator
+    path p10(r2.begin());
+    compare_paths(p1, p10);
+
+    test_container<const char, input_iterator_wrapper>
+      r3(s.c_str(), s.c_str() + s.size());
+    path p11(r3.begin(), r3.end());
+    compare_paths(p1, p11);
+
+    test_container<const char, input_iterator_wrapper>
+      r4(s.c_str(), s.c_str() + s.size() + 1); // includes null-terminator
+    path p12(r4.begin());
+    compare_paths(p1, p12);
+
+#if _GLIBCXX_USE_WCHAR_T
+    // Test with input iterators and const value_types
+    test_container<wchar_t, input_iterator_wrapper>
+      r5((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size());
+    path p13(r5.begin(), r5.end());
+    compare_paths(p1, p13);
+
+    test_container<wchar_t, input_iterator_wrapper>
+      r6((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size() + 1); // 
includes null-terminator
+    path p14(r6.begin());
+    compare_paths(p1, p14);
+
+    test_container<const wchar_t, input_iterator_wrapper>
+      r7(ws.c_str(), ws.c_str() + ws.size());
+    path p15(r7.begin(), r7.end());
+    compare_paths(p1, p15);
+
+    test_container<const wchar_t, input_iterator_wrapper>
+      r8(ws.c_str(), ws.c_str() + ws.size() + 1); // includes null-terminator
+    path p16(r8.begin());
+    compare_paths(p1, p16);
+#endif
   }
 }
 
diff --git 
a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc 
b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
new file mode 100644
index 0000000..43bc115
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
@@ -0,0 +1,56 @@
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++14 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <experimental/filesystem>
+#include <experimental/string_view>
+#include <string>
+#include <testsuite_fs.h>
+
+using std::experimental::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+  for (std::string s : __gnu_test::test_paths)
+  {
+    path p1 = s;
+    std::experimental::string_view sv(s);
+    path p2 = sv;
+    compare_paths(p1, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring ws(s.begin(), s.end());
+    path p3 = ws;
+    std::experimental::wstring_view wsv(ws);
+    path p4 = wsv;
+    compare_paths(p1, p4);
+#endif
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_fs.h 
b/libstdc++-v3/testsuite/util/testsuite_fs.h
index f1e0bfc..7d9b20c 100644
--- a/libstdc++-v3/testsuite/util/testsuite_fs.h
+++ b/libstdc++-v3/testsuite/util/testsuite_fs.h
@@ -23,7 +23,7 @@
 #define _TESTSUITE_FS_H 1
 
 #include <experimental/filesystem>
-#include <iostream>
+#include <fstream>
 #include <string>
 #include <cstdio>
 #include <stdlib.h>
@@ -40,7 +40,6 @@ namespace __gnu_test
   compare_paths(const std::experimental::filesystem::path& p1,
                const std::experimental::filesystem::path& p2)
   {
-    // std::cout << "Comparing " << p1 << " and " << p2 << std::endl;
     PATH_CHK( p1, p2, string );
     PATH_CHK( p1, p2, empty );
     PATH_CHK( p1, p2, has_root_path );
@@ -95,5 +94,23 @@ namespace __gnu_test
     return p;
   }
 
+  // RAII helper to remove a file on scope exit.
+  struct scoped_file
+  {
+    using path_type = std::experimental::filesystem::path;
+
+    enum adopt_file_t { adopt_file };
+
+    explicit
+    scoped_file(const path_type& p = nonexistent_path()) : path(p)
+    { std::ofstream{p.native()}; }
+
+    scoped_file(path_type p, adopt_file_t) : path(p) { }
+
+    ~scoped_file() { if (!path.empty()) remove(path); }
+
+    path_type path;
+  };
+
 } // namespace __gnu_test
 #endif

Reply via email to