Browse Source

Add Filesystem TS -- Complete

Add the completed std::experimental::filesystem implementation and tests.
The implementation supports C++11 or newer.

The TS is built as part of 'libc++experimental.a'. Users of the TS need to
manually link this library. Building and testing the TS can be disabled using
the CMake option '-DLIBCXX_ENABLE_FILESYSTEM=OFF'.

Currently 'libc++experimental.a' is not installed by default. To turn on the
installation of the library use '-DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON'.


git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@273034 91177308-0d34-0410-b5e6-96231b3b80d8
Eric Fiselier 9 years ago
parent
commit
6e9a694dce
100 changed files with 9986 additions and 8 deletions
  1. 8 1
      CMakeLists.txt
  2. 8 0
      docs/BuildingLibcxx.rst
  3. 10 0
      include/experimental/__config
  4. 2050 0
      include/experimental/filesystem
  5. 25 6
      include/iomanip
  6. 4 1
      lib/CMakeLists.txt
  7. 256 0
      src/experimental/filesystem/directory_iterator.cpp
  8. 754 0
      src/experimental/filesystem/operations.cpp
  9. 392 0
      src/experimental/filesystem/path.cpp
  10. 1 0
      test/CMakeLists.txt
  11. 101 0
      test/libcxx/experimental/filesystem/class.path/path.req/is_pathable.pass.cpp
  12. 3 0
      test/libcxx/experimental/filesystem/lit.local.cfg
  13. 22 0
      test/libcxx/experimental/filesystem/version.pass.cpp
  14. 30 0
      test/libcxx/test/config.py
  15. 1 0
      test/lit.site.cfg.in
  16. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/bad_symlink
  17. 0 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/afile3
  18. 0 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/dir3/file5
  19. 0 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/file4
  20. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/symlink_to_dir3
  21. 0 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/file1
  22. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/dir1/file2
  23. 0 0
      test/std/experimental/filesystem/Inputs/static_test_env/empty_file
  24. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/non_empty_file
  25. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/symlink_to_dir
  26. 1 0
      test/std/experimental/filesystem/Inputs/static_test_env/symlink_to_empty_file
  27. 97 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.cons.pass.cpp
  28. 113 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.mods.pass.cpp
  29. 82 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/comparisons.pass.cpp
  30. 89 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/path.pass.cpp
  31. 51 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/status.pass.cpp
  32. 50 0
      test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/symlink_status.pass.cpp
  33. 59 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/copy.pass.cpp
  34. 98 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/copy_assign.pass.cpp
  35. 246 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/ctor.pass.cpp
  36. 36 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/default_ctor.pass.cpp
  37. 117 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/increment.pass.cpp
  38. 62 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/move.pass.cpp
  39. 110 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/move_assign.pass.cpp
  40. 61 0
      test/std/experimental/filesystem/class.directory_iterator/directory_iterator.nonmembers/begin_end.pass.cpp
  41. 38 0
      test/std/experimental/filesystem/class.directory_iterator/types.pass.cpp
  42. 61 0
      test/std/experimental/filesystem/class.file_status/file_status.cons.pass.cpp
  43. 50 0
      test/std/experimental/filesystem/class.file_status/file_status.mods.pass.cpp
  44. 46 0
      test/std/experimental/filesystem/class.file_status/file_status.obs.pass.cpp
  45. 103 0
      test/std/experimental/filesystem/class.filesystem_error/filesystem_error.members.pass.cpp
  46. 104 0
      test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp
  47. 241 0
      test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp
  48. 37 0
      test/std/experimental/filesystem/class.path/path.member/path.assign/copy.pass.cpp
  49. 43 0
      test/std/experimental/filesystem/class.path/path.member/path.assign/move.pass.cpp
  50. 153 0
      test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp
  51. 126 0
      test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp
  52. 277 0
      test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp
  53. 35 0
      test/std/experimental/filesystem/class.path/path.member/path.construct/copy.pass.cpp
  54. 31 0
      test/std/experimental/filesystem/class.path/path.member/path.construct/default.pass.cpp
  55. 41 0
      test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp
  56. 83 0
      test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp
  57. 198 0
      test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp
  58. 57 0
      test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp
  59. 63 0
      test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
  60. 45 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/clear.pass.cpp
  61. 55 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/make_preferred.pass.cpp
  62. 72 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp
  63. 73 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_extension.pass.cpp
  64. 69 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp
  65. 81 0
      test/std/experimental/filesystem/class.path/path.member/path.modifiers/swap.pass.cpp
  66. 43 0
      test/std/experimental/filesystem/class.path/path.member/path.native.obs/c_str.pass.cpp
  67. 63 0
      test/std/experimental/filesystem/class.path/path.member/path.native.obs/named_overloads.pass.cpp
  68. 40 0
      test/std/experimental/filesystem/class.path/path.member/path.native.obs/native.pass.cpp
  69. 47 0
      test/std/experimental/filesystem/class.path/path.member/path.native.obs/operator_string.pass.cpp
  70. 113 0
      test/std/experimental/filesystem/class.path/path.member/path.native.obs/string_alloc.pass.cpp
  71. 32 0
      test/std/experimental/filesystem/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp
  72. 33 0
      test/std/experimental/filesystem/class.path/path.nonmember/append_op.pass.cpp
  73. 14 0
      test/std/experimental/filesystem/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp
  74. 14 0
      test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp
  75. 53 0
      test/std/experimental/filesystem/class.path/path.nonmember/path.factory.pass.cpp
  76. 66 0
      test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp
  77. 69 0
      test/std/experimental/filesystem/class.path/path.nonmember/path.io.unicode_bug.pass.cpp
  78. 50 0
      test/std/experimental/filesystem/class.path/path.nonmember/swap.pass.cpp
  79. 39 0
      test/std/experimental/filesystem/class.path/synop.pass.cpp
  80. 79 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/copy.pass.cpp
  81. 158 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/copy_assign.pass.cpp
  82. 240 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp
  83. 66 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/depth.pass.cpp
  84. 43 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/disable_recursion_pending.pass.cpp
  85. 228 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp
  86. 80 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/move.pass.cpp
  87. 163 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/move_assign.pass.cpp
  88. 93 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/pop.pass.cpp
  89. 145 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/recursion_pending.pass.cpp
  90. 61 0
      test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.nonmembers/begin_end.pass.cpp
  91. 75 0
      test/std/experimental/filesystem/fs.enum/check_bitmask_types.hpp
  92. 64 0
      test/std/experimental/filesystem/fs.enum/enum.copy_options.pass.cpp
  93. 46 0
      test/std/experimental/filesystem/fs.enum/enum.directory_options.pass.cpp
  94. 48 0
      test/std/experimental/filesystem/fs.enum/enum.file_type.pass.cpp
  95. 68 0
      test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp
  96. 12 0
      test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp
  97. 31 0
      test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp
  98. 117 0
      test/std/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
  99. 118 0
      test/std/experimental/filesystem/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
  100. 251 0
      test/std/experimental/filesystem/fs.op.funcs/fs.op.copy/copy.pass.cpp

+ 8 - 1
CMakeLists.txt

@@ -53,6 +53,8 @@ MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
 option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON)
 option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
 option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
+option(LIBCXX_ENABLE_FILESYSTEM
+        "Build filesystem as part of libc++experimental.a" ${LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY})
 option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
 option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
 set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
@@ -166,6 +168,11 @@ option(LIBCXX_CONFIGURE_IDE "Configure libcxx for use within an IDE"
 # Check option configurations
 #===============================================================================
 
+if (LIBCXX_ENABLE_FILESYSTEM AND NOT LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
+  message(FATAL_ERROR
+    "LIBCXX_ENABLE_FILESYSTEM cannot be turned on when LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF")
+endif()
+
 # Ensure LIBCXX_ENABLE_MONOTONIC_CLOCK is set to ON only when
 # LIBCXX_ENABLE_THREADS is on.
 if(LIBCXX_ENABLE_THREADS AND NOT LIBCXX_ENABLE_MONOTONIC_CLOCK)
@@ -302,7 +309,7 @@ add_compile_flags_if_supported(-nostdinc++)
 add_definitions(-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 add_compile_flags_if_supported(
     -Wall -W -Wwrite-strings
-    -Wno-unused-parameter -Wno-long-long
+    -Wno-unused-parameter -Wno-long-long -Wno-user-defined-literals
     -Werror=return-type)
 if (LIBCXX_ENABLE_WERROR)
   add_compile_flags_if_supported(-Werror)

+ 8 - 0
docs/BuildingLibcxx.rst

@@ -177,6 +177,14 @@ libc++experimental Specific Options
   Install libc++experimental.a alongside libc++.
 
 
+.. option:: LIBCXX_ENABLE_FILESYSTEM:BOOL
+
+  **Default**: ``LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY``
+
+  Build filesystem as part of libc++experimental.a. This allows filesystem
+  to be disabled without turning off the entire experimental library.
+
+
 .. _ABI Library Specific Options:
 
 ABI Library Specific Options

+ 10 - 0
include/experimental/__config

@@ -33,4 +33,14 @@
   namespace chrono { namespace experimental { inline namespace fundamentals_v1 {
 #define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } }
 
+#define _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
+    _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL namespace filesystem { \
+    inline namespace v1 {
+
+#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \
+    } } _LIBCPP_END_NAMESPACE_EXPERIMENTAL
+
+
+#define _VSTD_FS ::std::experimental::filesystem::v1
+
 #endif

+ 2050 - 0
include/experimental/filesystem

@@ -0,0 +1,2050 @@
+// -*- C++ -*-
+//===--------------------------- filesystem -------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP_EXPERIMENTAL_FILESYSTEM
+#define _LIBCPP_EXPERIMENTAL_FILESYSTEM
+/*
+    filesystem synopsis
+
+    namespace std { namespace experimental { namespace filesystem { inline namespace v1 {
+
+    class path;
+
+    void swap(path& lhs, path& rhs) _NOEXCEPT;
+    size_t hash_value(const path& p) _NOEXCEPT;
+
+    bool operator==(const path& lhs, const path& rhs) _NOEXCEPT;
+    bool operator!=(const path& lhs, const path& rhs) _NOEXCEPT;
+    bool operator< (const path& lhs, const path& rhs) _NOEXCEPT;
+    bool operator<=(const path& lhs, const path& rhs) _NOEXCEPT;
+    bool operator> (const path& lhs, const path& rhs) _NOEXCEPT;
+    bool operator>=(const path& lhs, const path& rhs) _NOEXCEPT;
+
+    path operator/ (const path& lhs, const path& rhs);
+
+    template <class charT, class traits>
+    basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>& os, const path& p);
+
+    template <class charT, class traits>
+    basic_istream<charT, traits>&
+    operator>>(basic_istream<charT, traits>& is, path& p);
+
+    template <class Source>
+      path u8path(const Source& source);
+    template <class InputIterator>
+      path u8path(InputIterator first, InputIterator last);
+
+    class filesystem_error;
+    class directory_entry;
+
+    class directory_iterator;
+
+    // enable directory_iterator range-based for statements
+    directory_iterator begin(directory_iterator iter) noexcept;
+    directory_iterator end(const directory_iterator&) noexcept;
+
+    class recursive_directory_iterator;
+
+    // enable recursive_directory_iterator range-based for statements
+    recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
+    recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
+
+    class file_status;
+
+    struct space_info
+    {
+      uintmax_t capacity;
+      uintmax_t free;
+      uintmax_t available;
+    };
+
+    enum class file_type;
+    enum class perms;
+    enum class copy_options;
+    enum class directory_options;
+
+    typedef chrono::time_point<trivial-clock>  file_time_type;
+
+    // operational functions
+
+    path absolute(const path& p, const path& base=current_path());
+
+    path canonical(const path& p, const path& base = current_path());
+    path canonical(const path& p, error_code& ec);
+    path canonical(const path& p, const path& base, error_code& ec);
+
+    void copy(const path& from, const path& to);
+    void copy(const path& from, const path& to, error_code& ec) _NOEXCEPT;
+    void copy(const path& from, const path& to, copy_options options);
+    void copy(const path& from, const path& to, copy_options options,
+                   error_code& ec) _NOEXCEPT;
+
+    bool copy_file(const path& from, const path& to);
+    bool copy_file(const path& from, const path& to, error_code& ec) _NOEXCEPT;
+    bool copy_file(const path& from, const path& to, copy_options option);
+    bool copy_file(const path& from, const path& to, copy_options option,
+                           error_code& ec) _NOEXCEPT;
+
+    void copy_symlink(const path& existing_symlink, const path& new_symlink);
+    void copy_symlink(const path& existing_symlink, const path& new_symlink,
+                              error_code& ec) _NOEXCEPT;
+
+    bool create_directories(const path& p);
+    bool create_directories(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool create_directory(const path& p);
+    bool create_directory(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool create_directory(const path& p, const path& attributes);
+    bool create_directory(const path& p, const path& attributes,
+                                  error_code& ec) _NOEXCEPT;
+
+    void create_directory_symlink(const path& to, const path& new_symlink);
+    void create_directory_symlink(const path& to, const path& new_symlink,
+                                          error_code& ec) _NOEXCEPT;
+
+    void create_hard_link(const path& to, const path& new_hard_link);
+    void create_hard_link(const path& to, const path& new_hard_link,
+                                  error_code& ec) _NOEXCEPT;
+
+    void create_symlink(const path& to, const path& new_symlink);
+    void create_symlink(const path& to, const path& new_symlink,
+                                error_code& ec) _NOEXCEPT;
+
+    path current_path();
+    path current_path(error_code& ec);
+    void current_path(const path& p);
+    void current_path(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool exists(file_status s) _NOEXCEPT;
+    bool exists(const path& p);
+    bool exists(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;
+
+    uintmax_t    file_size(const path& p);
+    uintmax_t    file_size(const path& p, error_code& ec) _NOEXCEPT;
+
+    uintmax_t    hard_link_count(const path& p);
+    uintmax_t    hard_link_count(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_block_file(file_status s) _NOEXCEPT;
+    bool is_block_file(const path& p);
+    bool is_block_file(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_character_file(file_status s) _NOEXCEPT;
+    bool is_character_file(const path& p);
+    bool is_character_file(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_directory(file_status s) _NOEXCEPT;
+    bool is_directory(const path& p);
+    bool is_directory(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_empty(const path& p);
+    bool is_empty(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_fifo(file_status s) _NOEXCEPT;
+    bool is_fifo(const path& p);
+    bool is_fifo(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_other(file_status s) _NOEXCEPT;
+    bool is_other(const path& p);
+    bool is_other(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_regular_file(file_status s) _NOEXCEPT;
+    bool is_regular_file(const path& p);
+    bool is_regular_file(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_socket(file_status s) _NOEXCEPT;
+    bool is_socket(const path& p);
+    bool is_socket(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool is_symlink(file_status s) _NOEXCEPT;
+    bool is_symlink(const path& p);
+    bool is_symlink(const path& p, error_code& ec) _NOEXCEPT;
+
+    file_time_type  last_write_time(const path& p);
+    file_time_type  last_write_time(const path& p, error_code& ec) _NOEXCEPT;
+    void last_write_time(const path& p, file_time_type new_time);
+    void last_write_time(const path& p, file_time_type new_time,
+                                 error_code& ec) _NOEXCEPT;
+
+    void permissions(const path& p, perms prms);
+    void permissions(const path& p, perms prms, error_code& ec) _NOEXCEPT;
+
+    path read_symlink(const path& p);
+    path read_symlink(const path& p, error_code& ec);
+
+    bool remove(const path& p);
+    bool remove(const path& p, error_code& ec) _NOEXCEPT;
+
+    uintmax_t    remove_all(const path& p);
+    uintmax_t    remove_all(const path& p, error_code& ec) _NOEXCEPT;
+
+    void rename(const path& from, const path& to);
+    void rename(const path& from, const path& to, error_code& ec) _NOEXCEPT;
+
+    void resize_file(const path& p, uintmax_t size);
+    void resize_file(const path& p, uintmax_t size, error_code& ec) _NOEXCEPT;
+
+    space_info   space(const path& p);
+    space_info   space(const path& p, error_code& ec) _NOEXCEPT;
+
+    file_status  status(const path& p);
+    file_status  status(const path& p, error_code& ec) _NOEXCEPT;
+
+    bool status_known(file_status s) _NOEXCEPT;
+
+    file_status  symlink_status(const path& p);
+    file_status  symlink_status(const path& p, error_code& ec) _NOEXCEPT;
+
+    path system_complete(const path& p);
+    path system_complete(const path& p, error_code& ec);
+
+    path temp_directory_path();
+    path temp_directory_path(error_code& ec);
+
+} } } }  // namespaces std::experimental::filesystem::v1
+
+*/
+
+#include <experimental/__config>
+#include <cstddef>
+#include <chrono>
+#include <iterator>
+#include <iosfwd>
+#include <locale>
+#include <memory>
+#include <stack>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <iomanip> // for quoted
+#include <experimental/string_view>
+
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+#define __cpp_lib_experimental_filesystem 201406
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+typedef chrono::time_point<std::chrono::system_clock>  file_time_type;
+
+struct _LIBCPP_TYPE_VIS space_info
+{
+  uintmax_t capacity;
+  uintmax_t free;
+  uintmax_t available;
+};
+
+enum class _LIBCPP_TYPE_VIS file_type : signed char
+{
+    none       = 0,
+    not_found  = -1,
+    regular    = 1,
+    directory  = 2,
+    symlink    = 3,
+    block      = 4,
+    character  = 5,
+    fifo       = 6,
+    socket     = 7,
+    unknown    = 8
+};
+
+enum class _LIBCPP_TYPE_VIS perms : unsigned
+{
+    none         = 0,
+
+    owner_read   = 0400,
+    owner_write  = 0200,
+    owner_exec   = 0100,
+    owner_all    = 0700,
+
+    group_read   = 040,
+    group_write  = 020,
+    group_exec   = 010,
+    group_all    = 070,
+
+    others_read  = 04,
+    others_write = 02,
+    others_exec  = 01,
+    others_all   = 07,
+
+    all          = 0777,
+
+    set_uid      = 04000,
+    set_gid      = 02000,
+    sticky_bit   = 01000,
+    mask         = 07777,
+    unknown      = 0xFFFF,
+
+    add_perms        = 0x10000,
+    remove_perms     = 0x20000,
+    resolve_symlinks = 0x40000
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR perms operator&(perms _LHS, perms _RHS)
+{ return static_cast<perms>(static_cast<unsigned>(_LHS) & static_cast<unsigned>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR perms operator|(perms _LHS, perms _RHS)
+{ return static_cast<perms>(static_cast<unsigned>(_LHS) | static_cast<unsigned>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR perms operator^(perms _LHS, perms _RHS)
+{ return static_cast<perms>(static_cast<unsigned>(_LHS) ^ static_cast<unsigned>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR perms operator~(perms _LHS)
+{ return static_cast<perms>(~static_cast<unsigned>(_LHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator&=(perms& _LHS, perms _RHS)
+{ return _LHS = _LHS & _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator|=(perms& _LHS, perms _RHS)
+{ return _LHS = _LHS | _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator^=(perms& _LHS, perms _RHS)
+{ return _LHS = _LHS ^ _RHS; }
+
+enum class _LIBCPP_TYPE_VIS copy_options : unsigned short
+{
+    none               = 0,
+    skip_existing      = 1,
+    overwrite_existing = 2,
+    update_existing    = 4,
+    recursive          = 8,
+    copy_symlinks      = 16,
+    skip_symlinks      = 32,
+    directories_only   = 64,
+    create_symlinks    = 128,
+    create_hard_links  = 256,
+    __in_recursive_copy = 512,
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR copy_options operator&(copy_options _LHS, copy_options _RHS)
+{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) & static_cast<unsigned short>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR copy_options operator|(copy_options _LHS, copy_options _RHS)
+{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) | static_cast<unsigned short>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR copy_options operator^(copy_options _LHS, copy_options _RHS)
+{ return static_cast<copy_options>(static_cast<unsigned short>(_LHS) ^ static_cast<unsigned short>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR copy_options operator~(copy_options _LHS)
+{ return static_cast<copy_options>(~static_cast<unsigned short>(_LHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS)
+{ return _LHS = _LHS & _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS)
+{ return _LHS = _LHS | _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS)
+{ return _LHS = _LHS ^ _RHS; }
+
+
+enum class directory_options : unsigned char
+{
+    none                     = 0,
+    follow_directory_symlink = 1,
+    skip_permission_denied   = 2
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR directory_options operator&(directory_options _LHS, directory_options _RHS)
+{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) & static_cast<unsigned char>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR directory_options operator|(directory_options _LHS, directory_options _RHS)
+{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) | static_cast<unsigned char>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR directory_options operator^(directory_options _LHS, directory_options _RHS)
+{ return static_cast<directory_options>(static_cast<unsigned char>(_LHS) ^ static_cast<unsigned char>(_RHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_CONSTEXPR directory_options operator~(directory_options _LHS)
+{ return static_cast<directory_options>(~static_cast<unsigned char>(_LHS)); }
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator&=(directory_options& _LHS, directory_options _RHS)
+{ return _LHS = _LHS & _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator|=(directory_options& _LHS, directory_options _RHS)
+{ return _LHS = _LHS | _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator^=(directory_options& _LHS, directory_options _RHS)
+{ return _LHS = _LHS ^ _RHS; }
+
+
+class _LIBCPP_TYPE_VIS file_status
+{
+public:
+    // constructors
+    _LIBCPP_INLINE_VISIBILITY
+    explicit file_status(file_type __ft = file_type::none,
+                         perms __prms   = perms::unknown) _NOEXCEPT
+      : __ft_(__ft), __prms_(__prms)
+    {}
+
+    file_status(const file_status&) _NOEXCEPT = default;
+    file_status(file_status&&) _NOEXCEPT = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    ~file_status() {}
+
+    file_status& operator=(const file_status&) _NOEXCEPT = default;
+    file_status& operator=(file_status&&) _NOEXCEPT = default;
+
+    // observers
+    _LIBCPP_ALWAYS_INLINE
+    file_type type() const _NOEXCEPT {
+        return __ft_;
+    }
+
+    _LIBCPP_ALWAYS_INLINE
+    perms permissions() const _NOEXCEPT {
+        return __prms_;
+    }
+
+    // modifiers
+    _LIBCPP_ALWAYS_INLINE
+    void type(file_type __ft) _NOEXCEPT {
+        __ft_ = __ft;
+    }
+
+    _LIBCPP_ALWAYS_INLINE
+    void permissions(perms __p) _NOEXCEPT {
+        __prms_ = __p;
+    }
+private:
+    file_type __ft_;
+    perms __prms_;
+};
+
+class _LIBCPP_TYPE_VIS directory_entry;
+
+template <class _Tp> struct __can_convert_char {
+  static const bool value = false;
+};
+template <> struct __can_convert_char<char> {
+    static const bool value = true;
+    using __char_type = char;
+};
+template <> struct __can_convert_char<wchar_t>  {
+    static const bool value = true;
+    using __char_type = wchar_t;
+};
+template <> struct __can_convert_char<char16_t> {
+    static const bool value = true;
+    using __char_type = char16_t;
+};
+template <> struct __can_convert_char<char32_t> {
+    static const bool value = true;
+    using __char_type = char32_t;
+};
+
+template <class _ECharT>
+typename enable_if<__can_convert_char<_ECharT>::value, bool>::type
+__is_separator(_ECharT __e) {
+    return __e == _ECharT('/');
+};
+
+struct _NullSentinal {};
+
+template <class _Tp>
+using _Void = void;
+
+template <class _Tp, class = void>
+struct __is_pathable_string : public false_type {};
+
+template <class _ECharT, class _Traits, class _Alloc>
+struct __is_pathable_string<basic_string<_ECharT, _Traits, _Alloc>,
+                            _Void<typename __can_convert_char<_ECharT>::__char_type>>
+: public __can_convert_char<_ECharT>
+{
+    using _Str = basic_string<_ECharT, _Traits, _Alloc>;
+    using _Base = __can_convert_char<_ECharT>;
+    static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
+    static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); }
+    static _ECharT __first_or_null(_Str const& __s) {
+        return __s.empty() ? _ECharT{} : __s[0];
+    }
+};
+
+template <class _Source,
+          class _DS = typename decay<_Source>::type,
+          class _UnqualPtrType = typename remove_const<
+              typename remove_pointer<_DS>::type>::type,
+          bool _IsCharPtr = is_pointer<_DS>::value &&
+                            __can_convert_char<_UnqualPtrType>::value
+        >
+struct __is_pathable_char_array : false_type {};
+
+template <class _Source, class _ECharT, class _UPtr>
+struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true>
+        : __can_convert_char<typename remove_const<_ECharT>::type>
+{
+  using _Base = __can_convert_char<typename remove_const<_ECharT>::type>;
+
+  static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }
+  static _ECharT const* __range_end(const _ECharT* __b)
+  {
+      using _Iter = const _ECharT*;
+      const _ECharT __sentinal = _ECharT{};
+      _Iter __e = __b;
+      for (; *__e != __sentinal; ++__e)
+          ;
+      return __e;
+  }
+
+  static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }
+};
+
+template <class _Iter, bool _IsIt = __is_input_iterator<_Iter>::value, class = void>
+struct __is_pathable_iter : false_type {};
+
+template <class _Iter>
+struct __is_pathable_iter<_Iter, true,
+        _Void<typename __can_convert_char<typename iterator_traits<_Iter>::value_type>::__char_type>>
+        : __can_convert_char<typename iterator_traits<_Iter>::value_type>
+{
+  using _ECharT = typename iterator_traits<_Iter>::value_type;
+  using _Base = __can_convert_char<_ECharT>;
+
+  static _Iter         __range_begin(_Iter __b) { return __b; }
+  static _NullSentinal __range_end(_Iter)       { return _NullSentinal{}; }
+
+  static _ECharT __first_or_null(_Iter __b) { return *__b; }
+};
+
+template <class _Tp, bool _IsStringT =  __is_pathable_string<_Tp>::value,
+                     bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,
+                     bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value
+         >
+struct __is_pathable : false_type {
+  static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
+};
+
+template <class _Tp>
+struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
+
+
+template <class _Tp>
+struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {};
+
+
+template <class _Tp>
+struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
+
+
+template <class _ECharT>
+struct _PathCVT {
+    static_assert(__can_convert_char<_ECharT>::value, "Char type not convertible");
+
+    typedef __narrow_to_utf8<sizeof(_ECharT)*__CHAR_BIT__> _Narrower;
+
+    static void __append_range(string& __dest, _ECharT const* __b, _ECharT const* __e)  {
+        _Narrower()(back_inserter(__dest), __b, __e);
+    }
+
+    template <class _Iter>
+    static void __append_range(string& __dest, _Iter __b, _Iter __e) {
+        static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
+        if (__b == __e) return;
+        basic_string<_ECharT> __tmp(__b, __e);
+        _Narrower()(back_inserter(__dest), __tmp.data(),
+                    __tmp.data() + __tmp.length());
+    }
+
+    template <class _Iter>
+    static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
+        static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
+        const _ECharT __sentinal = _ECharT{};
+        if (*__b == __sentinal) return;
+        basic_string<_ECharT> __tmp;
+        for (; *__b != __sentinal; ++__b)
+            __tmp.push_back(*__b);
+        _Narrower()(back_inserter(__dest), __tmp.data(),
+                    __tmp.data() + __tmp.length());
+    }
+
+    template <class _Source>
+    static void __append_source(string& __dest, _Source const& __s)
+    {
+        using _Traits = __is_pathable<_Source>;
+        __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));
+    }
+};
+
+template <>
+struct _PathCVT<char> {
+    template <class _Iter>
+    static void __append_range(string& __dest, _Iter __b, _Iter __e) {
+        for (; __b != __e; ++__b)
+            __dest.push_back(*__b);
+    }
+
+    template <class _Iter>
+    static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
+        const char __sentinal = char{};
+        for (; *__b != __sentinal; ++__b)
+            __dest.push_back(*__b);
+    }
+
+    template <class _Source>
+    static void __append_source(string& __dest, _Source const& __s)
+    {
+        using _Traits = __is_pathable<_Source>;
+        __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));
+    }
+};
+
+
+class _LIBCPP_TYPE_VIS path
+{
+    template <class _SourceOrIter, class _Tp = path&>
+    using _EnableIfPathable = typename
+        enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type;
+
+    template <class _Tp>
+    using _SourceChar = typename __is_pathable<_Tp>::__char_type;
+
+    template <class _Tp>
+    using _SourceCVT = _PathCVT<_SourceChar<_Tp>>;
+
+public:
+    typedef char value_type;
+    typedef basic_string<value_type> string_type;
+    static _LIBCPP_CONSTEXPR value_type preferred_separator = '/';
+
+    // constructors and destructor
+    _LIBCPP_INLINE_VISIBILITY path() _NOEXCEPT {}
+    _LIBCPP_INLINE_VISIBILITY path(const path& __p)      : __pn_(__p.__pn_) {}
+    _LIBCPP_INLINE_VISIBILITY path(path&& __p) _NOEXCEPT : __pn_(_VSTD::move(__p.__pn_)) {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    path(string_type&& __s) _NOEXCEPT : __pn_(_VSTD::move(__s)) {}
+
+    template <
+        class _Source,
+        class = _EnableIfPathable<_Source, void>
+        >
+    path(const _Source& __src) {
+        _SourceCVT<_Source>::__append_source(__pn_, __src);
+    }
+
+    template <class _InputIt>
+    path(_InputIt __first, _InputIt __last) {
+        typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+    }
+
+    // TODO Implement locale conversions.
+    template <class _Source,
+              class = _EnableIfPathable<_Source, void>
+             >
+        path(const _Source& __src, const locale& __loc);
+    template <class _InputIt>
+        path(_InputIt __first, _InputIt _last, const locale& __loc);
+
+    _LIBCPP_INLINE_VISIBILITY
+    ~path() = default;
+
+    // assignments
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator=(const path& __p) {
+        __pn_ = __p.__pn_;
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator=(path&& __p) _NOEXCEPT {
+        __pn_ = _VSTD::move(__p.__pn_);
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator=(string_type&& __s) _NOEXCEPT {
+        __pn_ = _VSTD::move(__s);
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& assign(string_type&& __s) _NOEXCEPT {
+        __pn_ = _VSTD::move(__s);
+        return *this;
+    }
+
+    template <class _Source>
+    _LIBCPP_INLINE_VISIBILITY
+    _EnableIfPathable<_Source>
+    operator=(const _Source& __src)
+    { return this->assign(__src); }
+
+
+    template <class _Source>
+    _EnableIfPathable<_Source>
+    assign(const _Source& __src) {
+        __pn_.clear();
+        _SourceCVT<_Source>::__append_source(__pn_, __src);
+        return *this;
+    }
+
+    template <class _InputIt>
+    path& assign(_InputIt __first, _InputIt __last) {
+        typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+        __pn_.clear();
+        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+        return *this;
+    }
+
+private:
+    template <class _ECharT>
+    void __append_sep_if_needed(_ECharT __first_or_null) {
+        const _ECharT __null_val = {};
+        bool __append_sep = !empty()                       &&
+                            !__is_separator(__pn_.back())  &&
+                            __first_or_null != __null_val  && // non-empty
+                            !__is_separator(__first_or_null);
+        if (__append_sep)
+            __pn_ += preferred_separator;
+    }
+
+public:
+    // appends
+    path& operator/=(const path& __p) {
+        __append_sep_if_needed(__p.empty() ? char{} : __p.__pn_[0]);
+        __pn_ += __p.native();
+        return *this;
+    }
+
+    template <class _Source>
+    _LIBCPP_INLINE_VISIBILITY
+    _EnableIfPathable<_Source>
+    operator/=(const _Source& __src) {
+        return this->append(__src);
+    }
+
+    template <class _Source>
+    _EnableIfPathable<_Source>
+    append(const _Source& __src) {
+        using _Traits = __is_pathable<_Source>;
+        using _CVT = _PathCVT<_SourceChar<_Source>>;
+        __append_sep_if_needed(_Traits::__first_or_null(__src));
+        _CVT::__append_source(__pn_, __src);
+        return *this;
+    }
+
+    template <class _InputIt>
+    path& append(_InputIt __first, _InputIt __last) {
+        typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+        static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
+        using _CVT = _PathCVT<_ItVal>;
+        if (__first != __last) {
+            __append_sep_if_needed(*__first);
+            _CVT::__append_range(__pn_, __first, __last);
+        }
+        return *this;
+    }
+
+    // concatenation
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator+=(const path& __x) {
+        __pn_ += __x.__pn_;
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator+=(const string_type& __x) {
+        __pn_ += __x;
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator+=(const value_type* __x) {
+        __pn_ += __x;
+        return *this;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    path& operator+=(value_type __x) {
+        __pn_ += __x;
+        return *this;
+    }
+
+
+    template <class _ECharT>
+    typename enable_if<__can_convert_char<_ECharT>::value, path&>::type
+    operator+=(_ECharT __x)
+    {
+        basic_string<_ECharT> __tmp;
+        __tmp += __x;
+        _PathCVT<_ECharT>::__append_source(__pn_, __tmp);
+        return *this;
+    }
+
+    template <class _Source>
+    _EnableIfPathable<_Source>
+    operator+=(const _Source& __x) {
+       return this->concat(__x);
+    }
+
+    template <class _Source>
+    _EnableIfPathable<_Source>
+    concat(const _Source& __x) {
+         _SourceCVT<_Source>::__append_source(__pn_, __x);
+        return *this;
+    }
+
+    template <class _InputIt>
+    path& concat(_InputIt __first, _InputIt __last) {
+        typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+        _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+        return *this;
+    }
+
+    // modifiers
+    _LIBCPP_INLINE_VISIBILITY
+    void clear() _NOEXCEPT {
+        __pn_.clear();
+    }
+
+    path& make_preferred() { return *this; }
+    path& remove_filename() { return *this = parent_path(); }
+
+    path& replace_filename(const path& __replacement) {
+        remove_filename();
+        return (*this /= __replacement);
+    }
+
+    path& replace_extension(const path& __replacement = path());
+
+    _LIBCPP_INLINE_VISIBILITY
+    void  swap(path& __rhs) _NOEXCEPT {
+        __pn_.swap(__rhs.__pn_);
+    }
+
+    // native format observers
+    _LIBCPP_INLINE_VISIBILITY
+    const string_type& native() const _NOEXCEPT {
+        return __pn_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    const value_type* c_str() const _NOEXCEPT { return __pn_.c_str(); }
+
+    _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_;  }
+
+    template <class _ECharT, class _Traits = char_traits<_ECharT>,
+              class _Allocator = allocator<_ECharT> >
+    basic_string<_ECharT, _Traits, _Allocator>
+    string(const _Allocator& __a = _Allocator()) const {
+        using _CVT = __widen_from_utf8<sizeof(_ECharT)*__CHAR_BIT__>;
+        using _Str = basic_string<_ECharT, _Traits, _Allocator>;
+        _Str __s(__a);
+        __s.reserve(__pn_.size());
+        _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());
+        return __s;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY std::string    string()    const { return __pn_; }
+    _LIBCPP_INLINE_VISIBILITY std::wstring   wstring()   const { return string<wchar_t>(); }
+    _LIBCPP_INLINE_VISIBILITY std::string    u8string()  const { return __pn_; }
+    _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const { return string<char16_t>(); }
+    _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { return string<char32_t>(); }
+
+    // generic format observers
+    template <class _ECharT, class _Traits = char_traits<_ECharT>,
+              class _Allocator = allocator<_ECharT>
+    >
+    basic_string<_ECharT, _Traits, _Allocator>
+    generic_string(const _Allocator& __a = _Allocator()) const {
+        return string<_ECharT, _Traits, _Allocator>(__a);
+    }
+
+    std::string    generic_string()    const { return __pn_; }
+    std::wstring   generic_wstring()   const { return string<wchar_t>(); }
+    std::string    generic_u8string()  const { return __pn_; }
+    std::u16string generic_u16string() const { return string<char16_t>(); }
+    std::u32string generic_u32string() const { return string<char32_t>(); }
+
+private:
+    _LIBCPP_FUNC_VIS int __compare(const value_type*) const;
+    _LIBCPP_FUNC_VIS string_view __root_name() const;
+    _LIBCPP_FUNC_VIS string_view __root_directory() const;
+    _LIBCPP_FUNC_VIS string_view __relative_path() const;
+    _LIBCPP_FUNC_VIS string_view __parent_path() const;
+    _LIBCPP_FUNC_VIS string_view __filename() const;
+    _LIBCPP_FUNC_VIS string_view __stem() const;
+    _LIBCPP_FUNC_VIS string_view __extension() const;
+
+public:
+    // compare
+    _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const _NOEXCEPT { return __compare(__p.c_str());}
+    _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const { return __compare(__s.c_str()); }
+    _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const  { return __compare(__s); }
+
+    // decomposition
+    _LIBCPP_INLINE_VISIBILITY path root_name()      const { return  __root_name().to_string(); }
+    _LIBCPP_INLINE_VISIBILITY path root_directory() const { return  __root_directory().to_string(); }
+    _LIBCPP_INLINE_VISIBILITY path root_path()      const { return root_name().append(__root_directory().to_string()); }
+    _LIBCPP_INLINE_VISIBILITY path relative_path()  const { return __relative_path().to_string(); }
+    _LIBCPP_INLINE_VISIBILITY path parent_path()    const { return __parent_path().to_string(); }
+    _LIBCPP_INLINE_VISIBILITY path filename()       const { return __filename().to_string(); }
+    _LIBCPP_INLINE_VISIBILITY path stem()           const { return __stem().to_string();}
+    _LIBCPP_INLINE_VISIBILITY path extension()      const { return __extension().to_string(); }
+
+    // query
+    _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT { return __pn_.empty(); }
+
+    _LIBCPP_INLINE_VISIBILITY bool has_root_name()      const { return !__root_name().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const { return !__root_directory().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_root_path()      const { return !(__root_name().empty() && __root_directory().empty()); }
+    _LIBCPP_INLINE_VISIBILITY bool has_relative_path()  const { return !__relative_path().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_parent_path()    const { return !__parent_path().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_filename()       const { return !__filename().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_stem()           const { return !__stem().empty(); }
+    _LIBCPP_INLINE_VISIBILITY bool has_extension()      const { return !__extension().empty(); }
+
+    _LIBCPP_INLINE_VISIBILITY bool is_absolute()        const { return has_root_directory(); }
+    _LIBCPP_INLINE_VISIBILITY bool is_relative()        const { return !is_absolute(); }
+
+    // iterators
+    class _LIBCPP_TYPE_VIS iterator;
+    typedef iterator const_iterator;
+
+    _LIBCPP_FUNC_VIS iterator begin() const;
+    _LIBCPP_FUNC_VIS iterator end() const;
+
+private:
+    inline _LIBCPP_INLINE_VISIBILITY
+    path& __assign_view(string_view const& __s) noexcept { __pn_ = __s.to_string(); return *this; }
+    string_type __pn_;
+};
+
+inline _LIBCPP_ALWAYS_INLINE
+void swap(path& __lhs, path& __rhs) _NOEXCEPT {
+    __lhs.swap(__rhs);
+}
+
+_LIBCPP_FUNC_VIS
+size_t hash_value(const path& __p) _NOEXCEPT;
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) == 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) != 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator<(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) < 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator<=(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) <= 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator>(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) > 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator>=(const path& __lhs, const path& __rhs) _NOEXCEPT
+{ return __lhs.compare(__rhs) >= 0; }
+
+inline _LIBCPP_INLINE_VISIBILITY
+path operator/(const path& __lhs, const path& __rhs) {
+    return path(__lhs) /= __rhs;
+}
+
+template <class _CharT, class _Traits>
+_LIBCPP_INLINE_VISIBILITY
+typename enable_if<is_same<_CharT, char>::value &&
+                   is_same<_Traits, char_traits<char>>::value,
+                   basic_ostream<_CharT, _Traits>&
+>::type
+operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+    __os << std::__quoted(__p.native());
+    return __os;
+}
+
+template <class _CharT, class _Traits>
+_LIBCPP_INLINE_VISIBILITY
+typename enable_if<!is_same<_CharT, char>::value ||
+                   !is_same<_Traits, char_traits<char>>::value,
+                   basic_ostream<_CharT, _Traits>&
+>::type
+operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+    __os << std::__quoted(__p.string<_CharT, _Traits>());
+    return __os;
+}
+
+template <class _CharT, class _Traits>
+_LIBCPP_INLINE_VISIBILITY
+basic_istream<_CharT, _Traits>&
+operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
+{
+    basic_string<_CharT, _Traits> __tmp;
+    __is >> __quoted(__tmp);
+    __p = __tmp;
+    return __is;
+}
+
+template <class _Source>
+_LIBCPP_INLINE_VISIBILITY
+typename enable_if<__is_pathable<_Source>::value, path>::type
+u8path(const _Source& __s){
+    static_assert(is_same<typename __is_pathable<_Source>::__char_type, char>::value,
+        "u8path(Source const&) requires Source have a character type of type 'char'");
+    return path(__s);
+}
+
+template <class _InputIt>
+_LIBCPP_INLINE_VISIBILITY
+typename enable_if<__is_pathable<_InputIt>::value, path>::type
+u8path(_InputIt __f, _InputIt __l) {
+    static_assert(is_same<typename __is_pathable<_InputIt>::__char_type, char>::value,
+        "u8path(Iter, Iter) requires Iter have a value_type of type 'char'");
+    return path(__f, __l);
+}
+
+class _LIBCPP_TYPE_VIS path::iterator
+{
+public:
+    typedef bidirectional_iterator_tag iterator_category;
+    typedef path                       value_type;
+    typedef std::ptrdiff_t             difference_type;
+    typedef const path*                pointer;
+    typedef const path&                reference;
+public:
+    _LIBCPP_INLINE_VISIBILITY
+    iterator() : __elem_(), __path_ptr_(nullptr), __pos_(0) {}
+
+    iterator(const iterator&) = default;
+    ~iterator() = default;
+
+    iterator& operator=(const iterator&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    reference operator*() const {
+        return __elem_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    pointer operator->() const {
+        return &__elem_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    iterator& operator++() {
+        return __increment();
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    iterator operator++(int) {
+        iterator __it(*this);
+        this->operator++();
+        return __it;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    iterator& operator--() {
+        return __decrement();
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    iterator operator--(int) {
+        iterator __it(*this);
+        this->operator--();
+        return __it;
+    }
+
+private:
+    friend class path;
+    friend bool operator==(const iterator&, const iterator&);
+
+    _LIBCPP_FUNC_VIS iterator& __increment();
+    _LIBCPP_FUNC_VIS iterator& __decrement();
+
+    path __elem_;
+    const path* __path_ptr_;
+    size_t __pos_;
+};
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) {
+    return __lhs.__path_ptr_ == __rhs.__path_ptr_ &&
+           __lhs.__pos_      == __rhs.__pos_;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(const path::iterator& __lhs, const path::iterator& __rhs) {
+    return !(__lhs == __rhs);
+}
+
+class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error
+{
+public:
+    _LIBCPP_INLINE_VISIBILITY
+    filesystem_error(const string& __what, error_code __ec)
+        : system_error(__ec, __what),
+          __paths_(make_shared<_Storage>(path(), path()))
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    filesystem_error(const string& __what, const path& __p1, error_code __ec)
+        : system_error(__ec, __what),
+        __paths_(make_shared<_Storage>(__p1, path()))
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    filesystem_error(const string& __what, const path& __p1, const path& __p2,
+                     error_code __ec)
+        : system_error(__ec, __what),
+          __paths_(make_shared<_Storage>(__p1, __p2))
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    const path& path1() const _NOEXCEPT {
+        return __paths_->first;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    const path& path2() const _NOEXCEPT {
+        return __paths_->second;
+    }
+
+    _LIBCPP_FUNC_VIS
+    ~filesystem_error() override; // key function
+
+    // TODO(ericwf): Create a custom error message.
+    //const char* what() const _NOEXCEPT;
+
+private:
+    typedef pair<path, path> _Storage;
+    shared_ptr<_Storage> __paths_;
+};
+
+// operational functions
+
+_LIBCPP_FUNC_VIS
+path __canonical(const path&, const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __copy(const path& __from, const path& __to, copy_options __opt,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __copy_file(const path& __from, const path& __to, copy_options __opt,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __copy_symlink(const path& __existing_symlink, const path& __new_symlink,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directories(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directory(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directory(const path& p, const path & attributes,
+        error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __create_directory_symlink(const path& __to, const path& __new_symlink,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __create_hard_link(const path& __to, const path& __new_hard_link,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __create_symlink(const path& __to, const path& __new_symlink,
+        error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __current_path(error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __current_path(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __equivalent(const path&, const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __file_size(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __hard_link_count(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __fs_is_empty(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+file_time_type __last_write_time(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __last_write_time(const path& p, file_time_type new_time,
+        error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __permissions(const path& p, perms prms, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __read_symlink(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+bool __remove(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __remove_all(const path& p, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __rename(const path& from, const path& to, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+void __resize_file(const path& p, uintmax_t size, error_code *ec=nullptr);
+_LIBCPP_FUNC_VIS
+space_info __space(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+file_status __status(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+file_status __symlink_status(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __system_complete(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __temp_directory_path(error_code *__ec=nullptr);
+
+inline _LIBCPP_INLINE_VISIBILITY
+path current_path() {
+    return __current_path();
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path current_path(error_code& __ec) {
+    return __current_path(&__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void current_path(const path& __p) {
+    __current_path(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void current_path(const path& __p, error_code& __ec) _NOEXCEPT {
+    __current_path(__p, &__ec);
+}
+
+_LIBCPP_FUNC_VIS
+path absolute(const path&, const path& __p2 = current_path());
+
+inline _LIBCPP_INLINE_VISIBILITY
+path canonical(const path& __p, const path& __base = current_path()) {
+    return __canonical(__p, __base);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path canonical(const path& __p, error_code& __ec) {
+    path __base = __current_path(&__ec);
+    if (__ec) return {};
+    return __canonical(__p, __base, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path canonical(const path& __p, const path& __base, error_code& __ec) {
+    return __canonical(__p, __base, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy(const path& __from, const path& __to) {
+    __copy(__from, __to, copy_options::none);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy(const path& __from, const path& __to, error_code& __ec) _NOEXCEPT {
+    __copy(__from, __to, copy_options::none, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy(const path& __from, const path& __to, copy_options __opt) {
+    __copy(__from, __to, __opt);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy(const path& __from, const path& __to,
+          copy_options __opt, error_code& __ec) _NOEXCEPT {
+    __copy(__from, __to, __opt, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool copy_file(const path& __from, const path& __to) {
+    return __copy_file(__from, __to, copy_options::none);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool copy_file(const path& __from, const path& __to, error_code& __ec) _NOEXCEPT {
+    return __copy_file(__from, __to, copy_options::none, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool copy_file(const path& __from, const path& __to, copy_options __opt) {
+    return __copy_file(__from, __to, __opt);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool copy_file(const path& __from, const path& __to,
+               copy_options __opt, error_code& __ec) _NOEXCEPT {
+    return __copy_file(__from, __to, __opt, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy_symlink(const path& __existing, const path& __new) {
+    __copy_symlink(__existing, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void copy_symlink(const path& __ext, const path& __new, error_code& __ec) _NOEXCEPT {
+    __copy_symlink(__ext, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directories(const path& __p) {
+    return __create_directories(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directories(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __create_directories(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directory(const path& __p) {
+    return __create_directory(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directory(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __create_directory(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directory(const path& __p, const path& __attrs) {
+    return __create_directory(__p, __attrs);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool create_directory(const path& __p, const path& __attrs, error_code& __ec) _NOEXCEPT {
+    return __create_directory(__p, __attrs, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_directory_symlink(const path& __to, const path& __new) {
+    __create_directory_symlink(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_directory_symlink(const path& __to, const path& __new,
+                              error_code& __ec) _NOEXCEPT {
+    __create_directory_symlink(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_hard_link(const path& __to, const path& __new) {
+    __create_hard_link(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_hard_link(const path& __to, const path& __new, error_code& __ec) _NOEXCEPT {
+    __create_hard_link(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_symlink(const path& __to, const path& __new) {
+    __create_symlink(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void create_symlink(const path& __to, const path& __new, error_code& __ec) _NOEXCEPT {
+    return __create_symlink(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool status_known(file_status __s) _NOEXCEPT {
+    return __s.type() != file_type::none;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool exists(file_status __s) _NOEXCEPT {
+    return status_known(__s) && __s.type() != file_type::not_found;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool exists(const path& __p) {
+    return exists(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool exists(const path& __p, error_code& __ec) _NOEXCEPT {
+    return exists(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool equivalent(const path& __p1, const path& __p2) {
+    return __equivalent(__p1, __p2);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool equivalent(const path& __p1, const path& __p2, error_code& __ec) _NOEXCEPT {
+    return __equivalent(__p1, __p2, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t file_size(const path& __p) {
+    return __file_size(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t file_size(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __file_size(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t hard_link_count(const path& __p) {
+    return __hard_link_count(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t hard_link_count(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __hard_link_count(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_block_file(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::block;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_block_file(const path& __p) {
+    return is_block_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_block_file(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_block_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_character_file(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::character;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_character_file(const path& __p) {
+    return is_character_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_character_file(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_character_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_directory(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::directory;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_directory(const path& __p) {
+    return is_directory(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_directory(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_directory(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_empty(const path& __p) {
+    return __fs_is_empty(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_empty(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __fs_is_empty(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_fifo(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::fifo;
+}
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_fifo(const path& __p) {
+    return is_fifo(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_fifo(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_fifo(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_regular_file(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::regular;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_regular_file(const path& __p) {
+    return is_regular_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_regular_file(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_regular_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_socket(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::socket;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_socket(const path& __p) {
+    return is_socket(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_socket(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_socket(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_symlink(file_status __s) _NOEXCEPT {
+    return __s.type() == file_type::symlink;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_symlink(const path& __p) {
+    return is_symlink(__symlink_status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_symlink(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_symlink(__symlink_status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_other(file_status __s) _NOEXCEPT {
+    return exists(__s)
+        && !is_regular_file(__s) && !is_directory(__s) && !is_symlink(__s);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_other(const path& __p) {
+    return is_other(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool is_other(const path& __p, error_code& __ec) _NOEXCEPT {
+    return is_other(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_time_type last_write_time(const path& __p) {
+    return __last_write_time(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_time_type last_write_time(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __last_write_time(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void last_write_time(const path& __p, file_time_type __t) {
+    __last_write_time(__p, __t);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void last_write_time(const path& __p, file_time_type __t, error_code& __ec) _NOEXCEPT {
+    __last_write_time(__p, __t, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void permissions(const path& __p, perms __prms) {
+    __permissions(__p, __prms);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void permissions(const path& __p, perms __prms, error_code& __ec)  {
+    __permissions(__p, __prms, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path read_symlink(const path& __p) {
+    return __read_symlink(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path read_symlink(const path& __p, error_code& __ec) {
+    return __read_symlink(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool remove(const path& __p) {
+    return __remove(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool remove(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __remove(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t remove_all(const path& __p) {
+    return __remove_all(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+uintmax_t remove_all(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __remove_all(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void rename(const path& __from, const path& __to) {
+    return __rename(__from, __to);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void rename(const path& __from, const path& __to, error_code& __ec) _NOEXCEPT {
+    return __rename(__from, __to, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void resize_file(const path& __p, uintmax_t __ns) {
+    return __resize_file(__p, __ns);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+void resize_file(const path& __p, uintmax_t __ns, error_code& __ec) _NOEXCEPT {
+    return __resize_file(__p, __ns, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+space_info space(const path& __p) {
+    return __space(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+space_info space(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __space(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_status status(const path& __p) {
+    return __status(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_status status(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __status(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_status symlink_status(const path& __p) {
+    return __symlink_status(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+file_status symlink_status(const path& __p, error_code& __ec) _NOEXCEPT {
+    return __symlink_status(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path system_complete(const path& __p) {
+    return __system_complete(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path system_complete(const path& __p, error_code& __ec) {
+    return __system_complete(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path temp_directory_path() {
+    return __temp_directory_path();
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path temp_directory_path(error_code& __ec) {
+    return __temp_directory_path(&__ec);
+}
+
+
+class directory_entry
+{
+    typedef _VSTD_FS::path _Path;
+
+public:
+    // constructors and destructors
+    directory_entry() _NOEXCEPT = default;
+    directory_entry(directory_entry const&) = default;
+    directory_entry(directory_entry&&) _NOEXCEPT = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit directory_entry(_Path const& __p) : __p_(__p) {}
+
+    ~directory_entry() {}
+
+    directory_entry& operator=(directory_entry const&) = default;
+    directory_entry& operator=(directory_entry&&) _NOEXCEPT = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    void assign(_Path const& __p) {
+        __p_ = __p;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void replace_filename(_Path const& __p) {
+        __p_ = __p_.parent_path() / __p;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    _Path const& path() const _NOEXCEPT {
+        return __p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    operator const _Path&() const _NOEXCEPT {
+        return __p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    file_status status() const {
+        return _VSTD_FS::status(__p_);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    file_status status(error_code& __ec) const _NOEXCEPT {
+        return _VSTD_FS::status(__p_, __ec);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    file_status symlink_status() const {
+        return _VSTD_FS::symlink_status(__p_);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    file_status symlink_status(error_code& __ec) const _NOEXCEPT {
+        return _VSTD_FS::symlink_status(__p_, __ec);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator< (directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ < __rhs.__p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator==(directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ == __rhs.__p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator!=(directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ != __rhs.__p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator<=(directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ <= __rhs.__p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator> (directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ > __rhs.__p_;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool operator>=(directory_entry const& __rhs) const _NOEXCEPT {
+        return __p_ >= __rhs.__p_;
+    }
+private:
+    _Path __p_;
+};
+
+
+class directory_iterator;
+class recursive_directory_iterator;
+class __dir_stream;
+
+class __dir_element_proxy {
+public:
+
+    inline _LIBCPP_INLINE_VISIBILITY
+    directory_entry operator*() { return _VSTD::move(__elem_); }
+
+private:
+    friend class directory_iterator;
+    friend class recursive_directory_iterator;
+    explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}
+    __dir_element_proxy(__dir_element_proxy&& __o) : __elem_(_VSTD::move(__o.__elem_)) {}
+    directory_entry __elem_;
+};
+
+class directory_iterator
+{
+public:
+    typedef directory_entry value_type;
+    typedef ptrdiff_t difference_type;
+    typedef value_type const* pointer;
+    typedef value_type const& reference;
+    typedef input_iterator_tag iterator_category;
+
+public:
+    //ctor & dtor
+    directory_iterator() _NOEXCEPT
+    { }
+
+    explicit directory_iterator(const path& __p)
+        : directory_iterator(__p, nullptr)
+    { }
+
+    directory_iterator(const path& __p, directory_options __opts)
+        : directory_iterator(__p, nullptr, __opts)
+    { }
+
+    directory_iterator(const path& __p, error_code& __ec) _NOEXCEPT
+        : directory_iterator(__p, &__ec)
+    { }
+
+    directory_iterator(const path& __p, directory_options __opts,
+                       error_code& __ec) _NOEXCEPT
+        : directory_iterator(__p, &__ec, __opts)
+    { }
+
+    directory_iterator(const directory_iterator&) = default;
+    directory_iterator(directory_iterator&&) = default;
+    directory_iterator& operator=(const directory_iterator&) = default;
+
+    directory_iterator& operator=(directory_iterator&& __o) _NOEXCEPT {
+        // non-default implementation provided to support self-move assign.
+        if (this != &__o) {
+            __imp_ = _VSTD::move(__o.__imp_);
+        }
+        return *this;
+    }
+
+    ~directory_iterator() = default;
+
+    const directory_entry& operator*() const {
+        _LIBCPP_ASSERT(__imp_, "The end iterator cannot be dereferenced");
+        return __deref();
+    }
+
+    const directory_entry* operator->() const
+    { return &**this; }
+
+    directory_iterator& operator++()
+    { return __increment(); }
+
+    __dir_element_proxy operator++(int) {
+        __dir_element_proxy __p(**this);
+        __increment();
+        return __p;
+    }
+
+    directory_iterator& increment(error_code& __ec) _NOEXCEPT
+    { return __increment(&__ec); }
+
+private:
+    friend bool operator==(const directory_iterator& __lhs,
+                           const directory_iterator& __rhs) _NOEXCEPT;
+
+    // construct the dir_stream
+    _LIBCPP_FUNC_VIS
+    directory_iterator(const path&, error_code *, directory_options = directory_options::none);
+    _LIBCPP_FUNC_VIS
+    directory_iterator& __increment(error_code * __ec = nullptr);
+    _LIBCPP_FUNC_VIS
+    const directory_entry& __deref() const;
+
+private:
+    shared_ptr<__dir_stream> __imp_;
+};
+
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(const directory_iterator& __lhs,
+                const directory_iterator& __rhs) _NOEXCEPT {
+    return __lhs.__imp_ == __rhs.__imp_;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(const directory_iterator& __lhs,
+                const directory_iterator& __rhs) _NOEXCEPT {
+    return !(__lhs == __rhs);
+}
+
+// enable directory_iterator range-based for statements
+inline _LIBCPP_INLINE_VISIBILITY
+directory_iterator begin(directory_iterator __iter) _NOEXCEPT {
+    return __iter;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+directory_iterator end(const directory_iterator&) _NOEXCEPT {
+    return directory_iterator();
+}
+
+class recursive_directory_iterator {
+public:
+    using value_type = directory_entry;
+    using difference_type = std::ptrdiff_t;
+    using pointer = directory_entry const *;
+    using reference = directory_entry const &;
+    using iterator_category = std::input_iterator_tag;
+
+public:
+    // constructors and destructor
+    _LIBCPP_INLINE_VISIBILITY
+    recursive_directory_iterator()  _NOEXCEPT
+        : __rec_(false)
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit recursive_directory_iterator(const path& __p,
+                directory_options __xoptions = directory_options::none)
+        : recursive_directory_iterator(__p, __xoptions,  nullptr)
+    { }
+
+    _LIBCPP_INLINE_VISIBILITY
+    recursive_directory_iterator(const path& __p,
+        directory_options __xoptions, error_code& __ec) _NOEXCEPT
+        : recursive_directory_iterator(__p, __xoptions, &__ec)
+    { }
+
+    _LIBCPP_INLINE_VISIBILITY
+    recursive_directory_iterator(const path& __p, error_code& __ec) _NOEXCEPT
+        : recursive_directory_iterator(__p, directory_options::none,  &__ec)
+    { }
+
+    recursive_directory_iterator(const recursive_directory_iterator&) = default;
+    recursive_directory_iterator(recursive_directory_iterator&&) = default;
+
+    recursive_directory_iterator &
+    operator=(const recursive_directory_iterator&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    recursive_directory_iterator &
+    operator=(recursive_directory_iterator&& __o) noexcept {
+        // non-default implementation provided to support self-move assign.
+        if (this != &__o) {
+            __imp_ = _VSTD::move(__o.__imp_);
+            __rec_ = __o.__rec_;
+        }
+        return *this;
+    }
+
+    ~recursive_directory_iterator() = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    const directory_entry& operator*() const
+    { return __deref(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    const directory_entry* operator->() const
+    { return &__deref(); }
+
+    recursive_directory_iterator& operator++()
+    { return __increment(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    __dir_element_proxy operator++(int) {
+        __dir_element_proxy __p(**this);
+        __increment();
+        return __p;
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    recursive_directory_iterator& increment(error_code& __ec) _NOEXCEPT
+    { return __increment(&__ec); }
+
+    _LIBCPP_FUNC_VIS directory_options options() const;
+    _LIBCPP_FUNC_VIS int  depth() const;
+
+    _LIBCPP_INLINE_VISIBILITY
+    void pop() { __pop(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void pop(error_code& __ec)
+    { __pop(&__ec); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool recursion_pending() const
+    { return __rec_; }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void disable_recursion_pending()
+    { __rec_ = false; }
+
+private:
+    recursive_directory_iterator(const path& __p, directory_options __opt,
+                                 error_code *__ec);
+
+    _LIBCPP_FUNC_VIS
+    const directory_entry& __deref() const;
+
+    _LIBCPP_FUNC_VIS
+    bool __try_recursion(error_code* __ec);
+
+    _LIBCPP_FUNC_VIS
+    void __advance(error_code* __ec=nullptr);
+
+    _LIBCPP_FUNC_VIS
+    recursive_directory_iterator& __increment(error_code *__ec=nullptr);
+
+    _LIBCPP_FUNC_VIS
+    void __pop(error_code* __ec=nullptr);
+
+    friend bool operator==(const recursive_directory_iterator&,
+                           const recursive_directory_iterator&) _NOEXCEPT;
+
+    struct __shared_imp;
+    shared_ptr<__shared_imp> __imp_;
+    bool __rec_;
+};                                     // class recursive_directory_iterator
+
+
+_LIBCPP_INLINE_VISIBILITY
+inline bool operator==(const recursive_directory_iterator& __lhs,
+                        const recursive_directory_iterator& __rhs) _NOEXCEPT
+{
+    return __lhs.__imp_ == __rhs.__imp_;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline bool operator!=(const recursive_directory_iterator& __lhs,
+                        const recursive_directory_iterator& __rhs) _NOEXCEPT
+{
+    return !(__lhs == __rhs);
+}
+// enable recursive_directory_iterator range-based for statements
+inline _LIBCPP_INLINE_VISIBILITY
+recursive_directory_iterator begin(recursive_directory_iterator __iter) _NOEXCEPT {
+    return __iter;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+recursive_directory_iterator end(const recursive_directory_iterator&) _NOEXCEPT {
+    return recursive_directory_iterator();
+}
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+#endif // _LIBCPP_EXPERIMENTAL_FILESYSTEM

+ 25 - 6
include/iomanip

@@ -512,8 +512,6 @@ put_time(const tm* __tm, const _CharT* __fmt)
     return __iom_t10<_CharT>(__tm, __fmt);
 }
 
-#if _LIBCPP_STD_VER > 11
-
 template <class _CharT, class _Traits, class _ForwardIterator>
 std::basic_ostream<_CharT, _Traits> &
 __quoted_output ( basic_ostream<_CharT, _Traits> &__os, 
@@ -631,22 +629,43 @@ quoted ( const _CharT *__s, _CharT __delim = _CharT('"'), _CharT __escape =_Char
     return __quoted_output_proxy<_CharT, const _CharT *> ( __s, __end, __delim, __escape );
 }
 
+
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_INLINE_VISIBILITY
 __quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
-quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
+__quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
 {
-    return __quoted_output_proxy<_CharT, 
-            typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> 
+    return __quoted_output_proxy<_CharT,
+            typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
                     ( __s.cbegin(), __s.cend (), __delim, __escape );
 }
 
 template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_INLINE_VISIBILITY
 __quoted_proxy<_CharT, _Traits, _Allocator>
-quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
+__quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
 {
     return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape );
 }
+
+
+#if _LIBCPP_STD_VER > 11
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_INLINE_VISIBILITY
+__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator>
+quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
+{
+    return __quoted(__s, __delim, __escape);
+}
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_INLINE_VISIBILITY
+__quoted_proxy<_CharT, _Traits, _Allocator>
+quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\'))
+{
+    return __quoted(__s, __delim, __escape);
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

+ 4 - 1
lib/CMakeLists.txt

@@ -154,7 +154,10 @@ set_target_properties(cxx
 
 if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
   file(GLOB LIBCXX_EXPERIMENTAL_SOURCES ../src/experimental/*.cpp)
-  add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES})
+  if (LIBCXX_ENABLE_FILESYSTEM)
+    file(GLOB LIBCXX_FILESYSTEM_SOURCES ../src/experimental/filesystem/*.cpp)
+  endif()
+  add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES} ${LIBCXX_FILESYSTEM_SOURCES})
   target_link_libraries(cxx_experimental cxx)
 
   set(experimental_flags "${LIBCXX_COMPILE_FLAGS}")

+ 256 - 0
src/experimental/filesystem/directory_iterator.cpp

@@ -0,0 +1,256 @@
+#include "experimental/filesystem"
+#include <dirent.h>
+#include <errno.h>
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+namespace { namespace detail {
+
+inline error_code capture_errno() {
+    _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
+    return error_code{errno, std::generic_category()};
+}
+
+template <class ...Args>
+inline bool capture_error_or_throw(std::error_code* user_ec,
+                                   const char* msg, Args&&... args)
+{
+    std::error_code my_ec = capture_errno();
+    if (user_ec) {
+        *user_ec = my_ec;
+        return true;
+    }
+    __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
+    return false;
+}
+
+template <class ...Args>
+inline bool set_or_throw(std::error_code& my_ec,
+                               std::error_code* user_ec,
+                               const char* msg, Args&&... args)
+{
+    if (user_ec) {
+        *user_ec = my_ec;
+        return true;
+    }
+    __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
+    return false;
+}
+
+typedef path::string_type string_type;
+
+
+inline string_type posix_readdir(DIR *dir_stream, error_code& ec) {
+    struct dirent* dir_entry_ptr = nullptr;
+    errno = 0; // zero errno in order to detect errors
+    if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
+        ec = capture_errno();
+        return {};
+    } else {
+        ec.clear();
+        return dir_entry_ptr->d_name;
+    }
+}
+
+}}                                                       // namespace detail
+
+using detail::set_or_throw;
+
+class __dir_stream {
+public:
+    __dir_stream() = delete;
+    __dir_stream& operator=(const __dir_stream&) = delete;
+
+    __dir_stream(__dir_stream&& other) noexcept
+        : __stream_(other.__stream_), __root_(std::move(other.__root_)),
+          __entry_(std::move(other.__entry_))
+    {
+        other.__stream_ = nullptr;
+    }
+
+
+    __dir_stream(const path& root, directory_options opts, error_code& ec)
+        : __stream_(nullptr),
+          __root_(root)
+    {
+        if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
+            ec = detail::capture_errno();
+            const bool allow_eacess =
+                bool(opts & directory_options::skip_permission_denied);
+            if (allow_eacess && ec.value() == EACCES)
+                ec.clear();
+            return;
+        }
+        advance(ec);
+    }
+
+    ~__dir_stream() noexcept
+      { if (__stream_) close(); }
+
+    bool good() const noexcept { return __stream_ != nullptr; }
+
+    bool advance(error_code &ec) {
+        while (true) {
+            auto str = detail::posix_readdir(__stream_,  ec);
+            if (str == "." || str == "..") {
+                continue;
+            } else if (ec || str.empty()) {
+                close();
+                return false;
+            } else {
+                __entry_.assign(__root_ / str);
+                return true;
+            }
+        }
+    }
+private:
+    std::error_code close() noexcept {
+        std::error_code m_ec;
+        if (::closedir(__stream_) == -1)
+           m_ec = detail::capture_errno();
+        __stream_ = nullptr;
+        return m_ec;
+    }
+
+    DIR * __stream_{nullptr};
+public:
+    path __root_;
+    directory_entry __entry_;
+};
+
+// directory_iterator
+
+directory_iterator::directory_iterator(const path& p, error_code *ec,
+                                       directory_options opts)
+{
+    std::error_code m_ec;
+    __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
+    if (ec) *ec = m_ec;
+    if (!__imp_->good()) {
+        __imp_.reset();
+        if (m_ec)
+            set_or_throw(m_ec, ec,
+                         "directory_iterator::directory_iterator(...)", p);
+    }
+}
+
+directory_iterator& directory_iterator::__increment(error_code *ec)
+{
+    _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
+    std::error_code m_ec;
+    if (!__imp_->advance(m_ec)) {
+        __imp_.reset();
+        if (m_ec)
+            set_or_throw(m_ec, ec, "directory_iterator::operator++()");
+    } else {
+        if (ec) ec->clear();
+    }
+    return *this;
+
+}
+
+directory_entry const& directory_iterator::__deref() const {
+    _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
+    return __imp_->__entry_;
+}
+
+// recursive_directory_iterator
+
+struct recursive_directory_iterator::__shared_imp {
+  stack<__dir_stream> __stack_;
+  directory_options   __options_;
+};
+
+recursive_directory_iterator::recursive_directory_iterator(const path& p,
+    directory_options opt, error_code *ec)
+    : __imp_(nullptr), __rec_(true)
+{
+    std::error_code m_ec;
+    __dir_stream new_s(p, opt, m_ec);
+    if (m_ec) set_or_throw(m_ec, ec, "recursive_directory_iterator", p);
+    if (m_ec || !new_s.good()) return;
+
+    __imp_ = _VSTD::make_shared<__shared_imp>();
+    __imp_->__options_ = opt;
+    __imp_->__stack_.push(_VSTD::move(new_s));
+}
+
+void recursive_directory_iterator::__pop(error_code* ec)
+{
+    _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
+    __imp_->__stack_.pop();
+    if (__imp_->__stack_.size() == 0) {
+        __imp_.reset();
+        if (ec) ec->clear();
+    } else {
+        __advance(ec);
+    }
+}
+
+directory_options recursive_directory_iterator::options() const {
+    return __imp_->__options_;
+}
+
+int recursive_directory_iterator::depth() const {
+    return __imp_->__stack_.size() - 1;
+}
+
+const directory_entry& recursive_directory_iterator::__deref() const {
+    return __imp_->__stack_.top().__entry_;
+}
+
+recursive_directory_iterator&
+recursive_directory_iterator::__increment(error_code *ec)
+{
+    if (recursion_pending()) {
+        if (__try_recursion(ec) || (ec && *ec))
+            return *this;
+    }
+    __rec_ = true;
+    __advance(ec);
+    return *this;
+}
+
+void recursive_directory_iterator::__advance(error_code* ec) {
+    const directory_iterator end_it;
+    auto& stack = __imp_->__stack_;
+    std::error_code m_ec;
+    while (stack.size() > 0) {
+        if (stack.top().advance(m_ec)) {
+            if (ec) ec->clear();
+            return;
+        }
+        if (m_ec) break;
+        stack.pop();
+    }
+    __imp_.reset();
+    if (m_ec)
+        set_or_throw(m_ec, ec, "recursive_directory_iterator::operator++()");
+}
+
+bool recursive_directory_iterator::__try_recursion(error_code *ec) {
+
+    bool rec_sym =
+        bool(options() & directory_options::follow_directory_symlink);
+    auto& curr_it = __imp_->__stack_.top();
+
+    if (is_directory(curr_it.__entry_.status()) &&
+        (!is_symlink(curr_it.__entry_.symlink_status()) || rec_sym))
+    {
+        std::error_code m_ec;
+        __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
+        if (new_it.good()) {
+            __imp_->__stack_.push(_VSTD::move(new_it));
+            return true;
+        }
+        if (m_ec) {
+            __imp_.reset();
+            set_or_throw(m_ec, ec,
+                               "recursive_directory_iterator::operator++()");
+        }
+    }
+    return false;
+}
+
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM

+ 754 - 0
src/experimental/filesystem/operations.cpp

@@ -0,0 +1,754 @@
+//===--------------------- filesystem/ops.cpp -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "experimental/filesystem"
+#include "iterator"
+#include "fstream"
+#include "type_traits"
+#include "random"  /* for unique_path */
+#include "cstdlib"
+#include "climits"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>  /* values for fchmodat */
+#if defined(__APPLE__)
+#include <sys/time.h> // for ::utimes as used in __last_write_time
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+filesystem_error::~filesystem_error() {}
+
+
+//                       POSIX HELPERS
+
+namespace detail { namespace  {
+
+using value_type = path::value_type;
+using string_type = path::string_type;
+
+
+
+inline std::error_code capture_errno() {
+    _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
+    std::error_code m_ec(errno, std::generic_category());
+    return m_ec;
+}
+
+void set_or_throw(std::error_code const& m_ec, std::error_code* ec,
+                  const char* msg, path const& p = {}, path const& p2 = {})
+{
+    if (ec) {
+        *ec = m_ec;
+    } else {
+        string msg_s("std::experimental::filesystem::");
+        msg_s += msg;
+        __libcpp_throw(filesystem_error(msg_s, p, p2, m_ec));
+    }
+}
+
+void set_or_throw(std::error_code* ec, const char* msg,
+                  path const& p = {}, path const& p2 = {})
+{
+    return set_or_throw(capture_errno(), ec, msg, p, p2);
+}
+
+perms posix_get_perms(const struct ::stat & st) noexcept {
+    return static_cast<perms>(st.st_mode) & perms::mask;
+}
+
+::mode_t posix_convert_perms(perms prms) {
+    return static_cast< ::mode_t>(prms & perms::mask);
+}
+
+file_status create_file_status(std::error_code& m_ec, path const& p,
+                               struct ::stat& path_stat,
+                               std::error_code* ec)
+{
+    if (ec) *ec = m_ec;
+    if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
+        return file_status(file_type::not_found);
+    }
+    else if (m_ec) {
+        set_or_throw(m_ec, ec, "posix_stat", p);
+        return file_status(file_type::none);
+    }
+    // else
+
+    file_status fs_tmp;
+    auto const mode = path_stat.st_mode;
+    if      (S_ISLNK(mode))  fs_tmp.type(file_type::symlink);
+    else if (S_ISREG(mode))  fs_tmp.type(file_type::regular);
+    else if (S_ISDIR(mode))  fs_tmp.type(file_type::directory);
+    else if (S_ISBLK(mode))  fs_tmp.type(file_type::block);
+    else if (S_ISCHR(mode))  fs_tmp.type(file_type::character);
+    else if (S_ISFIFO(mode)) fs_tmp.type(file_type::fifo);
+    else if (S_ISSOCK(mode)) fs_tmp.type(file_type::socket);
+    else                     fs_tmp.type(file_type::unknown);
+
+    fs_tmp.permissions(detail::posix_get_perms(path_stat));
+    return fs_tmp;
+}
+
+file_status posix_stat(path const & p, struct ::stat& path_stat,
+                       std::error_code* ec)
+{
+    std::error_code m_ec;
+    if (::stat(p.c_str(), &path_stat) == -1)
+        m_ec = detail::capture_errno();
+    return create_file_status(m_ec, p, path_stat, ec);
+}
+
+file_status posix_stat(path const & p, std::error_code* ec) {
+    struct ::stat path_stat;
+    return posix_stat(p, path_stat, ec);
+}
+
+file_status posix_lstat(path const & p, struct ::stat & path_stat,
+                        std::error_code* ec)
+{
+    std::error_code m_ec;
+    if (::lstat(p.c_str(), &path_stat) == -1)
+        m_ec = detail::capture_errno();
+    return create_file_status(m_ec, p, path_stat, ec);
+}
+
+file_status posix_lstat(path const & p, std::error_code* ec) {
+    struct ::stat path_stat;
+    return posix_lstat(p, path_stat, ec);
+}
+
+bool stat_equivalent(struct ::stat& st1, struct ::stat& st2) {
+    return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
+}
+
+//                           DETAIL::MISC
+
+
+bool copy_file_impl(const path& from, const path& to, perms from_perms,
+                    std::error_code *ec)
+{
+    std::ifstream in(from.c_str(), std::ios::binary);
+    std::ofstream out(to.c_str(),  std::ios::binary);
+
+    if (in.good() && out.good()) {
+        using InIt = std::istreambuf_iterator<char>;
+        using OutIt = std::ostreambuf_iterator<char>;
+        InIt bin(in);
+        InIt ein;
+        OutIt bout(out);
+        std::copy(bin, ein, bout);
+    }
+    if (out.fail() || in.fail()) {
+        set_or_throw(make_error_code(errc::operation_not_permitted),
+                     ec, "copy_file", from, to);
+        return false;
+    }
+    __permissions(to, from_perms, ec);
+    // TODO what if permissions fails?
+    return true;
+}
+
+}} // end namespace detail
+
+using detail::set_or_throw;
+
+path __canonical(path const & orig_p, const path& base, std::error_code *ec)
+{
+    path p = absolute(orig_p, base);
+    char buff[PATH_MAX + 1];
+    char *ret;
+    if ((ret = ::realpath(p.c_str(), buff)) == nullptr) {
+        set_or_throw(ec, "canonical", orig_p, base);
+        return {};
+    }
+    if (ec) ec->clear();
+    return {ret};
+}
+
+void __copy(const path& from, const path& to, copy_options options,
+            std::error_code *ec)
+{
+    const bool sym_status = bool(options &
+        (copy_options::create_symlinks | copy_options::skip_symlinks));
+
+    const bool sym_status2 = bool(options &
+        copy_options::copy_symlinks);
+
+    std::error_code m_ec;
+    struct ::stat f_st = {};
+    const file_status f = sym_status || sym_status2
+                                     ? detail::posix_lstat(from, f_st, &m_ec)
+                                     : detail::posix_stat(from,  f_st, &m_ec);
+    if (m_ec)
+        return set_or_throw(m_ec, ec, "copy", from, to);
+
+    struct ::stat t_st = {};
+    const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec)
+                                     : detail::posix_stat(to, t_st, &m_ec);
+
+    if (not status_known(t))
+        return set_or_throw(m_ec, ec, "copy", from, to);
+
+    if (!exists(f) || is_other(f) || is_other(t)
+        || (is_directory(f) && is_regular_file(t))
+        || detail::stat_equivalent(f_st, t_st))
+    {
+        return set_or_throw(make_error_code(errc::function_not_supported),
+                            ec, "copy", from, to);
+    }
+
+    if (ec) ec->clear();
+
+    if (is_symlink(f)) {
+        if (bool(copy_options::skip_symlinks & options)) {
+            // do nothing
+        } else if (not exists(t)) {
+            __copy_symlink(from, to, ec);
+        } else {
+            set_or_throw(make_error_code(errc::file_exists),
+                         ec, "copy", from, to);
+        }
+        return;
+    }
+    else if (is_regular_file(f)) {
+        if (bool(copy_options::directories_only & options)) {
+            // do nothing
+        }
+        else if (bool(copy_options::create_symlinks & options)) {
+            __create_symlink(from, to, ec);
+        }
+        else if (bool(copy_options::create_hard_links & options)) {
+            __create_hard_link(from, to, ec);
+        }
+        else if (is_directory(t)) {
+            __copy_file(from, to / from.filename(), options, ec);
+        } else {
+            __copy_file(from, to, options, ec);
+        }
+        return;
+    }
+    else if (is_directory(f)) {
+        if (not bool(copy_options::recursive & options) &&
+            bool(copy_options::__in_recursive_copy & options))
+        {
+            return;
+        }
+
+        if (!exists(t)) {
+            // create directory to with attributes from 'from'.
+            __create_directory(to, from, ec);
+            if (ec && *ec) { return; }
+        }
+        directory_iterator it = ec ? directory_iterator(from, *ec)
+                                   : directory_iterator(from);
+        if (ec && *ec) { return; }
+        std::error_code m_ec;
+        for (; it != directory_iterator(); it.increment(m_ec)) {
+            if (m_ec) return set_or_throw(m_ec, ec, "copy", from, to);
+            __copy(it->path(), to / it->path().filename(),
+                   options | copy_options::__in_recursive_copy, ec);
+            if (ec && *ec) { return; }
+        }
+    }
+}
+
+
+bool __copy_file(const path& from, const path& to, copy_options options,
+                 std::error_code *ec)
+{
+    if (ec) ec->clear();
+
+    std::error_code m_ec;
+    auto from_st = detail::posix_stat(from, &m_ec);
+    if (not is_regular_file(from_st)) {
+        if (not m_ec)
+            m_ec = make_error_code(errc::not_supported);
+        set_or_throw(m_ec, ec, "copy_file", from, to);
+        return false;
+    }
+
+    auto to_st = detail::posix_stat(to, &m_ec);
+    if (!status_known(to_st)) {
+        set_or_throw(m_ec, ec, "copy_file", from, to);
+        return false;
+    }
+
+    const bool to_exists = exists(to_st);
+    if (to_exists && bool(copy_options::skip_existing & options)) {
+        return false;
+    }
+    else if (to_exists && bool(copy_options::update_existing & options)) {
+        auto from_time = __last_write_time(from, ec);
+        if (ec && *ec) { return false; }
+        auto to_time = __last_write_time(to, ec);
+        if (ec && *ec) { return false; }
+        if (from_time <= to_time) {
+            return false;
+        }
+        return detail::copy_file_impl(from, to, from_st.permissions(), ec);
+    }
+    else if (!to_exists || bool(copy_options::overwrite_existing & options)) {
+        return detail::copy_file_impl(from, to, from_st.permissions(), ec);
+    }
+    else {
+        set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to);
+        return false;
+    }
+}
+
+void __copy_symlink(const path& existing_symlink, const path& new_symlink,
+                    std::error_code *ec)
+{
+    const path real_path(__read_symlink(existing_symlink, ec));
+    if (ec && *ec) { return; }
+    // NOTE: proposal says you should detect if you should call
+    // create_symlink or create_directory_symlink. I don't think this
+    // is needed with POSIX
+    __create_symlink(real_path, new_symlink, ec);
+}
+
+
+bool __create_directories(const path& p, std::error_code *ec)
+{
+    std::error_code m_ec;
+    auto const st = detail::posix_stat(p, &m_ec);
+    if (!status_known(st)) {
+        set_or_throw(m_ec, ec, "create_directories", p);
+        return false;
+    }
+    else if (is_directory(st)) {
+        if (ec) ec->clear();
+        return false;
+    }
+    else if (exists(st)) {
+        set_or_throw(make_error_code(errc::file_exists),
+                     ec, "create_directories", p);
+        return false;
+    }
+
+    const path parent = p.parent_path();
+    if (!parent.empty()) {
+        const file_status parent_st = status(parent, m_ec);
+        if (not status_known(parent_st)) {
+            set_or_throw(m_ec, ec, "create_directories", p);
+            return false;
+        }
+        if (not exists(parent_st)) {
+            __create_directories(parent, ec);
+            if (ec && *ec) { return false; }
+        }
+    }
+    return __create_directory(p, ec);
+}
+
+bool __create_directory(const path& p, std::error_code *ec)
+{
+    if (ec) ec->clear();
+    if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
+        return true;
+    if (errno != EEXIST || !is_directory(p))
+        set_or_throw(ec, "create_directory", p);
+    return false;
+}
+
+bool __create_directory(path const & p, path const & attributes,
+                        std::error_code *ec)
+{
+    struct ::stat attr_stat;
+    std::error_code mec;
+    auto st = detail::posix_stat(attributes, attr_stat, &mec);
+    if (!status_known(st)) {
+        set_or_throw(mec, ec, "create_directory", p, attributes);
+        return false;
+    }
+    if (ec) ec->clear();
+    if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
+        return true;
+    if (errno != EEXIST || !is_directory(p))
+        set_or_throw(ec, "create_directory", p, attributes);
+    return false;
+}
+
+void __create_directory_symlink(path const & from, path const & to,
+                                std::error_code *ec){
+    if (::symlink(from.c_str(), to.c_str()) != 0)
+        set_or_throw(ec, "create_directory_symlink", from, to);
+    else if (ec)
+        ec->clear();
+}
+
+void __create_hard_link(const path& from, const path& to, std::error_code *ec){
+    if (::link(from.c_str(), to.c_str()) == -1)
+        set_or_throw(ec, "create_hard_link", from, to);
+    else if (ec)
+        ec->clear();
+}
+
+void __create_symlink(path const & from, path const & to, std::error_code *ec) {
+
+    if (::symlink(from.c_str(), to.c_str()) == -1)
+        set_or_throw(ec, "create_symlink", from, to);
+    else if (ec)
+        ec->clear();
+}
+
+path __current_path(std::error_code *ec) {
+    auto size = ::pathconf(".", _PC_PATH_MAX);
+    _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
+
+    auto buff = std::unique_ptr<char[]>(new char[size + 1]);
+    char* ret;
+    if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr) {
+        set_or_throw(ec, "current_path");
+        return {};
+    }
+    if (ec) ec->clear();
+    return {buff.get()};
+}
+
+void __current_path(const path& p, std::error_code *ec) {
+    if (::chdir(p.c_str()) == -1)
+        set_or_throw(ec, "current_path", p);
+    else if (ec)
+        ec->clear();
+}
+
+bool __equivalent(const path& p1, const path& p2, std::error_code *ec)
+{
+    std::error_code ec1, ec2;
+    struct ::stat st1 = {};
+    struct ::stat st2 = {};
+    auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
+    auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
+
+    if ((!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2))) {
+        set_or_throw(make_error_code(errc::not_supported), ec,
+                     "equivalent", p1, p2);
+        return false;
+    }
+    if (ec) ec->clear();
+    return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
+}
+
+
+std::uintmax_t __file_size(const path& p, std::error_code *ec)
+{
+    std::error_code m_ec;
+    struct ::stat st;
+    file_status fst = detail::posix_stat(p, st, &m_ec);
+    if (!exists(fst) || !is_regular_file(fst)) {
+        if (!m_ec)
+            m_ec = make_error_code(errc::not_supported);
+        set_or_throw(m_ec, ec, "file_size", p);
+        return static_cast<uintmax_t>(-1);
+    }
+    // is_regular_file(p) == true
+    if (ec) ec->clear();
+    return static_cast<std::uintmax_t>(st.st_size);
+}
+
+std::uintmax_t __hard_link_count(const path& p, std::error_code *ec)
+{
+    std::error_code m_ec;
+    struct ::stat st;
+    detail::posix_stat(p, st, &m_ec);
+    if (m_ec) {
+        set_or_throw(m_ec, ec, "hard_link_count", p);
+        return static_cast<std::uintmax_t>(-1);
+    }
+    if (ec) ec->clear();
+    return static_cast<std::uintmax_t>(st.st_nlink);
+}
+
+
+bool __fs_is_empty(const path& p, std::error_code *ec)
+{
+    if (ec) ec->clear();
+    std::error_code m_ec;
+    struct ::stat pst;
+    auto st = detail::posix_stat(p, pst, &m_ec);
+    if (is_directory(st))
+        return directory_iterator(p) == directory_iterator{};
+    else if (is_regular_file(st))
+        return static_cast<std::uintmax_t>(pst.st_size) == 0;
+    // else
+    set_or_throw(m_ec, ec, "is_empty", p);
+    return false;
+}
+
+
+file_time_type __last_write_time(const path& p, std::error_code *ec)
+{
+    using Clock = file_time_type::clock;
+    std::error_code m_ec;
+    struct ::stat st;
+    detail::posix_stat(p, st, &m_ec);
+    if (m_ec) {
+        set_or_throw(m_ec, ec, "last_write_time", p);
+        return file_time_type::min();
+    }
+    if (ec) ec->clear();
+    return Clock::from_time_t(static_cast<std::time_t>(st.st_mtime));
+}
+
+
+void __last_write_time(const path& p, file_time_type new_time,
+                       std::error_code *ec)
+{
+    using namespace std::chrono;
+    std::error_code m_ec;
+
+#if defined(__APPLE__)
+    // FIXME: Use utimensat when it becomes available on OS X.
+    // This implementation has a race condition between determining the
+    // last access time and attempting to set it to the same value using
+    // ::utimes
+    using Clock = file_time_type::clock;
+    struct ::stat st;
+    file_status fst = detail::posix_stat(p, st, &m_ec);
+    if (m_ec && !status_known(fst)) {
+        set_or_throw(m_ec, ec, "last_write_time", p);
+        return;
+    }
+    auto write_dur = new_time.time_since_epoch();
+    auto write_sec = duration_cast<seconds>(write_dur);
+    auto access_dur = Clock::from_time_t(st.st_atime).time_since_epoch();
+    auto access_sec = duration_cast<seconds>(access_dur);
+    struct ::timeval tbuf[2];
+    tbuf[0].tv_sec = access_sec.count();
+    tbuf[0].tv_usec = duration_cast<microseconds>(access_dur - access_sec).count();
+    tbuf[1].tv_sec = write_sec.count();
+    tbuf[1].tv_usec = duration_cast<microseconds>(write_dur - write_sec).count();
+    if (::utimes(p.c_str(), tbuf) == -1) {
+        m_ec = detail::capture_errno();
+    }
+#else
+    auto dur_since_epoch = new_time.time_since_epoch();
+    auto sec_since_epoch = duration_cast<seconds>(dur_since_epoch);
+    auto ns_since_epoch = duration_cast<nanoseconds>(dur_since_epoch - sec_since_epoch);
+    struct ::timespec tbuf[2];
+    tbuf[0].tv_sec = 0;
+    tbuf[0].tv_nsec = UTIME_OMIT;
+    tbuf[1].tv_sec = sec_since_epoch.count();
+    tbuf[1].tv_nsec = ns_since_epoch.count();
+    if (::utimensat(AT_FDCWD, p.c_str(), tbuf, 0) == -1) {
+        m_ec = detail::capture_errno();
+    }
+#endif
+    if (m_ec)
+        set_or_throw(m_ec, ec, "last_write_time", p);
+    else if (ec)
+        ec->clear();
+}
+
+
+void __permissions(const path& p, perms prms, std::error_code *ec)
+{
+
+    const bool resolve_symlinks = bool(perms::resolve_symlinks & prms);
+    const bool add_perms = bool(perms::add_perms & prms);
+    const bool remove_perms = bool(perms::remove_perms & prms);
+
+    _LIBCPP_ASSERT(!(add_perms && remove_perms),
+                   "Both add_perms and remove_perms are set");
+
+    std::error_code m_ec;
+    file_status st = detail::posix_lstat(p, &m_ec);
+    if (m_ec) return set_or_throw(m_ec, ec, "permissions", p);
+
+    const bool set_sym_perms = is_symlink(st) && !resolve_symlinks;
+
+    if ((resolve_symlinks && is_symlink(st)) && (add_perms || remove_perms)) {
+        st = detail::posix_stat(p, &m_ec);
+        if (m_ec) return set_or_throw(m_ec, ec, "permissions", p);
+    }
+
+    prms = prms & perms::mask;
+    if (add_perms)
+        prms |= st.permissions();
+    else if (remove_perms)
+        prms = st.permissions() & ~prms;
+    auto real_perms = detail::posix_convert_perms(prms);
+
+# if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
+    const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
+    if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
+# else
+    if (set_sym_perms)
+        return set_or_throw(make_error_code(errc::operation_not_supported),
+                            ec, "permissions", p);
+    if (::chmod(p.c_str(), real_perms) == -1) {
+# endif
+        return set_or_throw(ec, "permissions", p);
+    }
+    if (ec) ec->clear();
+}
+
+
+path __read_symlink(const path& p, std::error_code *ec) {
+    char buff[PATH_MAX + 1];
+    std::error_code m_ec;
+    ::ssize_t ret;
+    if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
+        set_or_throw(ec, "read_symlink", p);
+        return {};
+    }
+    _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
+    _LIBCPP_ASSERT(ret > 0, "TODO");
+    if (ec) ec->clear();
+    buff[ret] = 0;
+    return {buff};
+}
+
+
+bool __remove(const path& p, std::error_code *ec) {
+    if (ec) ec->clear();
+    if (::remove(p.c_str()) == -1) {
+        set_or_throw(ec, "remove", p);
+        return false;
+    }
+    return true;
+}
+
+namespace {
+
+std::uintmax_t remove_all_impl(path const & p, std::error_code& ec)
+{
+    const auto npos = static_cast<std::uintmax_t>(-1);
+    const file_status st = __symlink_status(p, &ec);
+    if (ec) return npos;
+     std::uintmax_t count = 1;
+    if (is_directory(st)) {
+        for (directory_iterator it(p, ec); !ec && it != directory_iterator();
+             it.increment(ec)) {
+            auto other_count = remove_all_impl(it->path(), ec);
+            if (ec) return npos;
+            count += other_count;
+        }
+        if (ec) return npos;
+    }
+    if (!__remove(p, &ec)) return npos;
+    return count;
+}
+
+} // end namespace
+
+std::uintmax_t __remove_all(const path& p, std::error_code *ec) {
+    std::error_code mec;
+    auto count = remove_all_impl(p, mec);
+    if (mec) {
+        set_or_throw(mec, ec, "remove_all", p);
+        return static_cast<std::uintmax_t>(-1);
+    }
+    if (ec) ec->clear();
+    return count;
+}
+
+void __rename(const path& from, const path& to, std::error_code *ec) {
+    if (::rename(from.c_str(), to.c_str()) == -1)
+        set_or_throw(ec, "rename", from, to);
+    else if (ec)
+        ec->clear();
+}
+
+void __resize_file(const path& p, std::uintmax_t size, std::error_code *ec) {
+    if (::truncate(p.c_str(), static_cast<long>(size)) == -1)
+        set_or_throw(ec, "resize_file", p);
+    else if (ec)
+        ec->clear();
+}
+
+space_info __space(const path& p, std::error_code *ec) {
+    space_info si;
+    struct statvfs m_svfs;
+    if (::statvfs(p.c_str(), &m_svfs) == -1)  {
+        set_or_throw(ec, "space", p);
+        si.capacity = si.free = si.available =
+            static_cast<std::uintmax_t>(-1);
+        return si;
+    }
+    if (ec) ec->clear();
+    // Multiply with overflow checking.
+    auto do_mult = [&](std::uintmax_t& out, fsblkcnt_t other) {
+      out = other * m_svfs.f_frsize;
+      if (out / other != m_svfs.f_frsize || other == 0)
+          out = static_cast<std::uintmax_t>(-1);
+    };
+    do_mult(si.capacity, m_svfs.f_blocks);
+    do_mult(si.free, m_svfs.f_bfree);
+    do_mult(si.available, m_svfs.f_bavail);
+    return si;
+}
+
+file_status __status(const path& p, std::error_code *ec) {
+    return detail::posix_stat(p, ec);
+}
+
+file_status __symlink_status(const path& p, std::error_code *ec) {
+    return detail::posix_lstat(p, ec);
+}
+
+path __system_complete(const path& p, std::error_code *ec) {
+    if (ec) ec->clear();
+    return absolute(p, current_path());
+}
+
+path __temp_directory_path(std::error_code *ec) {
+    const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
+    const char* ret = nullptr;
+    for (auto & ep : env_paths)  {
+        if ((ret = std::getenv(ep)))
+            break;
+    }
+    path p(ret ? ret : "/tmp");
+    std::error_code m_ec;
+    if (is_directory(p, m_ec)) {
+        if (ec) ec->clear();
+        return p;
+    }
+    if (!m_ec || m_ec == make_error_code(errc::no_such_file_or_directory))
+        m_ec = make_error_code(errc::not_a_directory);
+    set_or_throw(m_ec, ec, "temp_directory_path");
+    return {};
+}
+
+// An absolute path is composed according to the table in [fs.op.absolute].
+path absolute(const path& p, const path& base) {
+    auto root_name = p.root_name();
+    auto root_dir = p.root_directory();
+
+    if (!root_name.empty() && !root_dir.empty())
+      return p;
+
+    auto abs_base = base.is_absolute() ? base : absolute(base);
+
+    /* !has_root_name && !has_root_dir */
+    if (root_name.empty() && root_dir.empty())
+    {
+      return abs_base / p;
+    }
+    else if (!root_name.empty()) /* has_root_name && !has_root_dir */
+    {
+      return  root_name / abs_base.root_directory()
+              /
+              abs_base.relative_path() / p.relative_path();
+    }
+    else /* !has_root_name && has_root_dir */
+    {
+      if (abs_base.has_root_name())
+        return abs_base.root_name() / p;
+      // else p is absolute,  return outside of block
+    }
+    return p;
+}
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM

+ 392 - 0
src/experimental/filesystem/path.cpp

@@ -0,0 +1,392 @@
+//===--------------------- filesystem/path.cpp ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "experimental/filesystem"
+#include "experimental/string_view"
+#include "utility"
+
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+_LIBCPP_CONSTEXPR path::value_type path::preferred_separator;
+
+
+namespace { namespace parser
+{
+
+using string_type = string_view;
+using value_type = path::value_type;
+
+using string_view_pair = pair<string_view, string_view>;
+
+// status reporting
+constexpr size_t npos = static_cast<size_t>(-1);
+
+inline bool good(size_t pos) { return pos != npos; }
+
+// lexical elements
+constexpr value_type preferred_separator = path::preferred_separator;
+constexpr value_type const * preferred_separator_str = "/";
+constexpr value_type const * dot = ".";
+
+// forward //
+bool is_separator(string_type const &, size_t);
+bool is_root_name(const string_type&, size_t);
+bool is_root_directory(string_type const &, size_t);
+bool is_trailing_separator(string_type const &, size_t);
+
+size_t start_of(string_type const &, size_t);
+size_t end_of(string_type const &, size_t);
+
+size_t root_name_start(const string_type& s);
+size_t root_name_end(const string_type&);
+
+size_t root_directory_start(string_type const &);
+size_t root_directory_end(string_type const &);
+
+string_view_pair separate_filename(string_type const &);
+string_view extract_raw(string_type const &, size_t);
+string_view extract_preferred(string_type const &, size_t);
+
+inline bool is_separator(const string_type& s, size_t pos) {
+    return (pos < s.size() && s[pos] == preferred_separator);
+}
+
+inline bool is_root_name(const string_type& s, size_t pos) {
+  return good(pos) && pos == 0 ? root_name_start(s) == pos : false;
+}
+
+inline bool is_root_directory(const string_type& s, size_t pos) {
+    return good(pos) ? root_directory_start(s) == pos : false;
+}
+
+inline bool is_trailing_separator(const string_type& s, size_t pos) {
+    return (pos < s.size() && is_separator(s, pos) &&
+            end_of(s, pos) == s.size()-1 &&
+            !is_root_directory(s, pos) && !is_root_name(s, pos));
+}
+
+size_t start_of(const string_type& s, size_t pos) {
+    if (pos >= s.size()) return npos;
+    bool in_sep = (s[pos] == preferred_separator);
+    while (pos - 1 < s.size() &&
+        (s[pos-1] == preferred_separator) == in_sep)
+    { --pos; }
+    if (pos == 2 && !in_sep && s[0] == preferred_separator &&
+        s[1] == preferred_separator)
+    { return 0; }
+    return pos;
+}
+
+size_t end_of(const string_type& s, size_t pos) {
+    if (pos >= s.size()) return npos;
+    // special case for root name
+    if (pos == 0 && is_root_name(s, pos)) return root_name_end(s);
+    bool in_sep = (s[pos] == preferred_separator);
+    while (pos + 1 < s.size() && (s[pos+1] == preferred_separator) == in_sep)
+    { ++pos; }
+    return pos;
+}
+
+inline size_t root_name_start(const string_type& s) {
+    return good(root_name_end(s)) ? 0 : npos;
+}
+
+size_t root_name_end(const string_type& s) {
+    if (s.size() < 2 || s[0] != preferred_separator
+        || s[1] != preferred_separator) {
+        return npos;
+    }
+    if (s.size() == 2) {
+        return 1;
+    }
+    size_t index = 2; // current position
+    if (s[index] == preferred_separator) {
+        return npos;
+    }
+    while (index + 1 < s.size() && s[index+1] != preferred_separator) {
+        ++index;
+    }
+    return index;
+}
+
+size_t root_directory_start(const string_type& s) {
+    size_t e = root_name_end(s);
+    if (!good(e))
+    return is_separator(s, 0) ? 0 : npos;
+    return is_separator(s, e + 1) ? e + 1 : npos;
+}
+
+size_t root_directory_end(const string_type& s) {
+    size_t st = root_directory_start(s);
+    if (!good(st)) return npos;
+    size_t index = st;
+    while (index + 1 < s.size() && s[index + 1] == preferred_separator)
+      { ++index; }
+    return index;
+}
+
+string_view_pair separate_filename(string_type const & s) {
+    if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};
+    auto pos = s.find_last_of('.');
+    if (pos == string_type::npos) return string_view_pair{s, string_view{}};
+    return string_view_pair{s.substr(0, pos), s.substr(pos)};
+}
+
+inline string_view extract_raw(const string_type& s, size_t pos) {
+    size_t end_i = end_of(s, pos);
+    if (!good(end_i)) return string_view{};
+    return string_view(s).substr(pos, end_i - pos + 1);
+}
+
+string_view extract_preferred(const string_type& s, size_t pos) {
+    string_view raw = extract_raw(s, pos);
+    if (raw.empty())
+        return raw;
+    if (is_trailing_separator(s, pos))
+        return string_view{dot};
+    if (is_separator(s, pos) && !is_root_name(s, pos))
+        return string_view(preferred_separator_str);
+    return raw;
+}
+
+}} // namespace parser
+
+
+////////////////////////////////////////////////////////////////////////////////
+//                            path_view_iterator
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+
+struct path_view_iterator {
+  const string_view __s_;
+  size_t __pos_;
+
+  explicit path_view_iterator(string_view const& __s) : __s_(__s), __pos_(__s_.empty() ? parser::npos : 0) {}
+  explicit path_view_iterator(string_view const& __s, size_t __p) : __s_(__s), __pos_(__p) {}
+
+  string_view operator*() const {
+    return parser::extract_preferred(__s_, __pos_);
+  }
+
+  path_view_iterator& operator++() {
+    increment();
+    return *this;
+  }
+
+  path_view_iterator& operator--() {
+    decrement();
+    return *this;
+  }
+
+  void increment() {
+    if (__pos_ == parser::npos) return;
+    while (! set_position(parser::end_of(__s_, __pos_)+1))
+        ;
+    return;
+  }
+
+  void decrement() {
+    if (__pos_ == 0) {
+      set_position(0);
+    }
+    else if (__pos_ == parser::npos) {
+      auto const str_size = __s_.size();
+      set_position(parser::start_of(
+          __s_, str_size != 0 ? str_size - 1 : str_size));
+    } else {
+      while (!set_position(parser::start_of(__s_, __pos_-1)))
+        ;
+    }
+  }
+
+  bool set_position(size_t pos) {
+    if (pos >= __s_.size()) {
+      __pos_ = parser::npos;
+    } else {
+      __pos_ = pos;
+    }
+    return valid_iterator_position();
+  }
+
+  bool valid_iterator_position() const {
+    if (__pos_ == parser::npos) return true; // end position is valid
+    return (!parser::is_separator      (__s_, __pos_) ||
+          parser::is_root_directory    (__s_, __pos_) ||
+          parser::is_trailing_separator(__s_, __pos_) ||
+          parser::is_root_name         (__s_, __pos_));
+  }
+
+  bool is_end() const { return __pos_ == parser::npos; }
+
+  inline bool operator==(path_view_iterator const& __p) {
+      return __pos_ == __p.__pos_;
+  }
+};
+
+path_view_iterator pbegin(path const& p) {
+    return path_view_iterator(p.native());
+}
+
+path_view_iterator pend(path const& p) {
+    path_view_iterator __p(p.native());
+    __p.__pos_ = parser::npos;
+    return __p;
+}
+
+} // end namespace
+///////////////////////////////////////////////////////////////////////////////
+//                            path definitions
+///////////////////////////////////////////////////////////////////////////////
+
+path & path::replace_extension(path const & replacement)
+{
+    path p = extension();
+    if (not p.empty()) {
+      __pn_.erase(__pn_.size() - p.native().size());
+    }
+    if (!replacement.empty()) {
+        if (replacement.native()[0] != '.') {
+            __pn_ += ".";
+        }
+        __pn_.append(replacement.__pn_);
+    }
+    return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// path.decompose
+
+string_view path::__root_name() const
+{
+    return parser::is_root_name(__pn_, 0)
+      ? parser::extract_preferred(__pn_, 0)
+      : string_view{};
+}
+
+string_view path::__root_directory() const
+{
+    auto start_i = parser::root_directory_start(__pn_);
+    if(!parser::good(start_i)) {
+        return {};
+    }
+    return parser::extract_preferred(__pn_, start_i);
+}
+
+string_view path::__relative_path() const
+{
+    if (empty()) {
+        return {__pn_};
+    }
+    auto end_i = parser::root_directory_end(__pn_);
+    if (not parser::good(end_i)) {
+        end_i = parser::root_name_end(__pn_);
+    }
+    if (not parser::good(end_i)) {
+        return {__pn_};
+    }
+    return string_view(__pn_).substr(end_i+1);
+}
+
+string_view path::__parent_path() const
+{
+    if (empty() || pbegin(*this) == --pend(*this)) {
+        return {};
+    }
+    auto end_it = --(--pend(*this));
+    auto end_i = parser::end_of(__pn_, end_it.__pos_);
+    return string_view(__pn_).substr(0, end_i+1);
+}
+
+string_view path::__filename() const
+{
+    return empty() ? string_view{} : *--pend(*this);
+}
+
+string_view path::__stem() const
+{
+    return parser::separate_filename(__filename()).first;
+}
+
+string_view path::__extension() const
+{
+    return parser::separate_filename(__filename()).second;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.comparisons
+int path::__compare(const value_type* __s) const {
+    path_view_iterator thisIter(this->native());
+    path_view_iterator sIter(__s);
+    while (!thisIter.is_end() && !sIter.is_end()) {
+        int res = (*thisIter).compare(*sIter);
+        if (res != 0) return res;
+        ++thisIter; ++sIter;
+    }
+    if (thisIter.is_end() && sIter.is_end())
+        return 0;
+    if (thisIter.is_end())
+        return -1;
+    return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.nonmembers
+size_t hash_value(const path& __p) _NOEXCEPT {
+  path_view_iterator thisIter(__p.native());
+  struct HashPairT {
+    size_t first;
+    size_t second;
+  };
+  HashPairT hp = {0, 0};
+  std::hash<string_view> hasher;
+  std::__scalar_hash<decltype(hp)> pair_hasher;
+  while (!thisIter.is_end()) {
+    hp.second = hasher(*thisIter);
+    hp.first = pair_hasher(hp);
+    ++thisIter;
+  }
+  return hp.first;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.itr
+path::iterator path::begin() const
+{
+    path_view_iterator pit = pbegin(*this);
+    iterator it;
+    it.__path_ptr_ = this;
+    it.__pos_ = pit.__pos_;
+    it.__elem_.__assign_view(*pit);
+    return it;
+}
+
+path::iterator path::end() const
+{
+    iterator it{};
+    it.__path_ptr_ = this;
+    it.__pos_ = parser::npos;
+    return it;
+}
+
+path::iterator& path::iterator::__increment() {
+  path_view_iterator it(__path_ptr_->native(), __pos_);
+  it.increment();
+  __pos_ = it.__pos_;
+  __elem_.__assign_view(*it);
+  return *this;
+}
+
+path::iterator& path::iterator::__decrement() {
+  path_view_iterator it(__path_ptr_->native(), __pos_);
+  it.decrement();
+  __pos_ = it.__pos_;
+  __elem_.__assign_view(*it);
+  return *this;
+}
+
+_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM

+ 1 - 0
test/CMakeLists.txt

@@ -11,6 +11,7 @@ set(LIBCXX_LIT_VARIANT "libcxx" CACHE STRING
 
 pythonize_bool(LIBCXX_ENABLE_EXCEPTIONS)
 pythonize_bool(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
+pythonize_bool(LIBCXX_ENABLE_FILESYSTEM)
 pythonize_bool(LIBCXX_ENABLE_RTTI)
 pythonize_bool(LIBCXX_ENABLE_SHARED)
 pythonize_bool(LIBCXX_BUILD_32_BITS)

+ 101 - 0
test/libcxx/experimental/filesystem/class.path/path.req/is_pathable.pass.cpp

@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// template <class Tp> struct __is_pathable
+
+// [path.req]
+// In addition to the requirements (5), function template parameters named
+// `Source` shall be one of:
+// * basic_string<_ECharT, _Traits, _Alloc>
+// * InputIterator with a value_type of _ECharT
+// * A character array, which points to a NTCTS after array-to-pointer decay.
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+namespace fs = std::experimental::filesystem;
+
+using fs::__is_pathable;
+
+template <class Tp>
+struct Identity { typedef Tp type; };
+
+template <class Source>
+Identity<Source> CheckSourceType(Source const&);
+
+template <class Tp>
+using GetSourceType = typename decltype(CheckSourceType(std::declval<Tp>()))::type;
+
+template <class Tp, class Exp,
+          class ExpQual = typename std::remove_const<Exp>::type>
+using CheckPass = std::is_same<ExpQual, GetSourceType<Tp>>;
+
+template <class Source>
+using CheckPassSource = std::integral_constant<bool,
+        CheckPass<Source&,        Source>::value &&
+        CheckPass<Source const&,  Source>::value &&
+        CheckPass<Source&&,       Source>::value &&
+        CheckPass<Source const&&, Source>::value
+  >;
+
+template <class CharT>
+struct MakeTestType {
+  using value_type = CharT;
+  using string_type = std::basic_string<CharT>;
+  using string_type2 = std::basic_string<CharT, std::char_traits<CharT>, min_allocator<CharT>>;
+  using cstr_type = CharT* const;
+  using const_cstr_type = const CharT*;
+  using array_type = CharT[25];
+  using const_array_type = const CharT[25];
+  using iter_type = input_iterator<CharT*>;
+  using bad_iter_type = input_iterator<signed char*>;
+
+  template <class TestT>
+  static void AssertPathable() {
+    static_assert(__is_pathable<TestT>::value, "");
+    static_assert(CheckPassSource<TestT>::value, "cannot pass as Source const&");
+    ASSERT_SAME_TYPE(CharT, typename __is_pathable<TestT>::__char_type);
+  }
+
+  template <class TestT>
+  static void AssertNotPathable() {
+    static_assert(!__is_pathable<TestT>::value, "");
+  }
+
+  static void Test() {
+    AssertPathable<string_type>();
+    AssertPathable<string_type2>();
+    AssertPathable<cstr_type>();
+    AssertPathable<const_cstr_type>();
+    AssertPathable<array_type>();
+    AssertPathable<const_array_type>();
+    AssertPathable<iter_type>();
+
+    AssertNotPathable<CharT>();
+    AssertNotPathable<bad_iter_type>();
+    AssertNotPathable<signed char*>();
+  }
+};
+
+int main() {
+  MakeTestType<char>::Test();
+  MakeTestType<wchar_t>::Test();
+  MakeTestType<char16_t>::Test();
+  MakeTestType<char32_t>::Test();
+}

+ 3 - 0
test/libcxx/experimental/filesystem/lit.local.cfg

@@ -0,0 +1,3 @@
+# Disable all of the filesystem tests if the correct feature is not available.
+if 'c++filesystem' not in config.available_features:
+  config.unsupported = True

+ 22 - 0
test/libcxx/experimental/filesystem/version.pass.cpp

@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+#include <experimental/filesystem>
+
+#ifndef _LIBCPP_VERSION
+#error _LIBCPP_VERSION not defined
+#endif
+
+int main()
+{
+}

+ 30 - 0
test/libcxx/test/config.py

@@ -103,6 +103,7 @@ class Configuration(object):
         self.configure_execute_external()
         self.configure_ccache()
         self.configure_compile_flags()
+        self.configure_filesystem_compile_flags()
         self.configure_link_flags()
         self.configure_env()
         self.configure_color_diagnostics()
@@ -427,6 +428,35 @@ class Configuration(object):
           self.config.available_features.add('libcpp-abi-unstable')
           self.cxx.compile_flags += ['-D_LIBCPP_ABI_UNSTABLE']
 
+    def configure_filesystem_compile_flags(self):
+        enable_fs = self.get_lit_bool('enable_filesystem', default=False)
+        if not enable_fs:
+            return
+        enable_experimental = self.get_lit_bool('enable_experimental', default=False)
+        if not enable_experimental:
+            self.lit_config.fatal(
+                'filesystem is enabled but libc++experimental.a is not.')
+        self.config.available_features.add('c++filesystem')
+        static_env = os.path.join(self.libcxx_src_root, 'test', 'std',
+                                  'experimental', 'filesystem', 'Inputs', 'static_test_env')
+        assert os.path.isdir(static_env)
+        self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="%s"' % static_env]
+
+        dynamic_env = os.path.join(self.libcxx_obj_root, 'test',
+                                   'filesystem', 'Output', 'dynamic_env')
+        if not os.path.isdir(dynamic_env):
+            os.makedirs(dynamic_env)
+        self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="%s"' % dynamic_env]
+        self.env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env)
+
+        dynamic_helper = os.path.join(self.libcxx_src_root, 'test', 'support',
+                                      'filesystem_dynamic_test_helper.py')
+        assert os.path.isfile(dynamic_helper)
+
+        self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER="%s %s"'
+                                   % (sys.executable, dynamic_helper)]
+
+
     def configure_link_flags(self):
         no_default_flags = self.get_lit_bool('no_default_flags', False)
         if not no_default_flags:

+ 1 - 0
test/lit.site.cfg.in

@@ -6,6 +6,7 @@ config.libcxx_obj_root          = "@LIBCXX_BINARY_DIR@"
 config.cxx_library_root         = "@LIBCXX_LIBRARY_DIR@"
 config.enable_exceptions        = "@LIBCXX_ENABLE_EXCEPTIONS@"
 config.enable_experimental      = "@LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY@"
+config.enable_filesystem        = "@LIBCXX_ENABLE_FILESYSTEM@"
 config.enable_rtti              = "@LIBCXX_ENABLE_RTTI@"
 config.enable_shared            = "@LIBCXX_ENABLE_SHARED@"
 config.enable_32bit             = "@LIBCXX_BUILD_32_BITS@"

+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/bad_symlink

@@ -0,0 +1 @@
+dne

+ 0 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/afile3


+ 0 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/dir3/file5


+ 0 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/file4


+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/dir2/symlink_to_dir3

@@ -0,0 +1 @@
+dir3

+ 0 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/file1


+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/dir1/file2

@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

+ 0 - 0
test/std/experimental/filesystem/Inputs/static_test_env/empty_file


+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/non_empty_file

@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/symlink_to_dir

@@ -0,0 +1 @@
+dir1

+ 1 - 0
test/std/experimental/filesystem/Inputs/static_test_env/symlink_to_empty_file

@@ -0,0 +1 @@
+empty_file

+ 97 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.cons.pass.cpp

@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+//          directory_entry() noexcept = default;
+//          directory_entry(const directory_entry&) = default;
+//          directory_entry(directory_entry&&) noexcept = default;
+// explicit directory_entry(const path);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+void test_default_ctor()
+{
+  using namespace fs;
+  // Default
+  {
+    static_assert(std::is_nothrow_default_constructible<directory_entry>::value,
+                  "directory_entry must have a nothrow default constructor");
+    directory_entry e;
+    assert(e.path() == path());
+  }
+}
+
+
+void test_copy_ctor()
+{
+  using namespace fs;
+  // Copy
+  {
+    static_assert(std::is_copy_constructible<directory_entry>::value,
+                  "directory_entry must be copy constructible");
+    static_assert(!std::is_nothrow_copy_constructible<directory_entry>::value,
+                  "directory_entry's copy constructor cannot be noexcept");
+    const path p("foo/bar/baz");
+    const directory_entry e(p);
+    assert(e.path() == p);
+    directory_entry e2(e);
+    assert(e.path() == p);
+    assert(e2.path() == p);
+  }
+
+}
+
+void test_move_ctor()
+{
+  using namespace fs;
+  // Move
+  {
+    static_assert(std::is_nothrow_move_constructible<directory_entry>::value,
+                  "directory_entry must be nothrow move constructible");
+    const path p("foo/bar/baz");
+    directory_entry e(p);
+    assert(e.path() == p);
+    directory_entry e2(std::move(e));
+    assert(e2.path() == p);
+    assert(e.path()  != p); // Testing moved from state.
+  }
+}
+
+void test_path_ctor() {
+  using namespace fs;
+  {
+    static_assert(std::is_constructible<directory_entry, const path&>::value,
+                  "directory_entry must be constructible from path");
+    static_assert(!std::is_nothrow_constructible<directory_entry, const path&>::value,
+                  "directory_entry constructor should not be noexcept");
+    static_assert(!std::is_convertible<path const&, directory_entry>::value,
+                  "directory_entry constructor should be explicit");
+  }
+  {
+    const path p("foo/bar/baz");
+    const directory_entry e(p);
+    assert(p == e.path());
+  }
+}
+
+int main() {
+  test_default_ctor();
+  test_copy_ctor();
+  test_move_ctor();
+  test_path_ctor();
+}

+ 113 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.mods.pass.cpp

@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+// directory_entry& operator=(directory_entry const&) = default;
+// directory_entry& operator=(directory_entry&&) noexcept = default;
+// void assign(path const&);
+// void replace_filename(path const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+void test_copy_assign_operator()
+{
+  using namespace fs;
+  // Copy
+  {
+    static_assert(std::is_copy_assignable<directory_entry>::value,
+                  "directory_entry must be copy assignable");
+    static_assert(!std::is_nothrow_copy_assignable<directory_entry>::value,
+                  "directory_entry's copy assignment cannot be noexcept");
+    const path p("foo/bar/baz");
+    const path p2("abc");
+    const directory_entry e(p);
+    directory_entry e2;
+    assert(e.path() == p && e2.path() == path());
+    e2 = e;
+    assert(e.path() == p && e2.path() == p);
+    directory_entry e3(p2);
+    e2 = e3;
+    assert(e2.path() == p2 && e3.path() == p2);
+  }
+}
+
+
+void test_move_assign_operator()
+{
+  using namespace fs;
+  // Copy
+  {
+    static_assert(std::is_nothrow_move_assignable<directory_entry>::value,
+                  "directory_entry is noexcept move assignable");
+    const path p("foo/bar/baz");
+    const path p2("abc");
+    directory_entry e(p);
+    directory_entry e2(p2);
+    assert(e.path() == p && e2.path() == p2);
+    e2 = std::move(e);
+    assert(e2.path() == p);
+    assert(e.path() != p); // testing moved from state
+  }
+}
+
+void test_path_assign_method()
+{
+  using namespace fs;
+  const path p("foo/bar/baz");
+  const path p2("abc");
+  directory_entry e(p);
+  {
+    static_assert(std::is_same<decltype(e.assign(p)), void>::value,
+                  "return type should be void");
+    static_assert(noexcept(e.assign(p)) == false, "operation must not be noexcept");
+  }
+  {
+    assert(e.path() == p);
+    e.assign(p2);
+    assert(e.path() == p2 && e.path() != p);
+    e.assign(p);
+    assert(e.path() == p && e.path() != p2);
+  }
+}
+
+void test_replace_filename_method()
+{
+  using namespace fs;
+  const path p("/path/to/foo.exe");
+  const path replace("bar.out");
+  const path expect("/path/to/bar.out");
+  directory_entry e(p);
+  {
+    static_assert(noexcept(e.replace_filename(replace)) == false,
+                  "operation cannot be noexcept");
+    static_assert(std::is_same<decltype(e.replace_filename(replace)), void>::value,
+                  "operation must return void");
+  }
+  {
+    assert(e.path() == p);
+    e.replace_filename(replace);
+    assert(e.path() == expect);
+  }
+}
+
+int main() {
+  test_copy_assign_operator();
+  test_move_assign_operator();
+  test_path_assign_method();
+  test_replace_filename_method();
+}

+ 82 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/comparisons.pass.cpp

@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+// bool operator==(directory_entry const&) const noexcept;
+// bool operator!=(directory_entry const&) const noexcept;
+// bool operator< (directory_entry const&) const noexcept;
+// bool operator<=(directory_entry const&) const noexcept;
+// bool operator> (directory_entry const&) const noexcept;
+// bool operator>=(directory_entry const&) const noexcept;
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+#define CHECK_OP(Op) \
+  static_assert(std::is_same<decltype(ce. operator Op (ce)), bool>::value, ""); \
+  static_assert(noexcept(ce.operator Op (ce)), "Operation must be noexcept" )
+
+void test_comparison_signatures() {
+  using namespace fs;
+  path const p("foo/bar/baz");
+  // Check that the operators are member functions with the correct signatures.
+  {
+    directory_entry const ce(p);
+    CHECK_OP(==);
+    CHECK_OP(!=);
+    CHECK_OP(< );
+    CHECK_OP(<=);
+    CHECK_OP(> );
+    CHECK_OP(>=);
+  }
+}
+#undef CHECK_OP
+
+// The actual semantics of the comparisons are testing via paths operators.
+void test_comparisons_simple() {
+  using namespace fs;
+  typedef std::pair<path, path> TestType;
+  TestType TestCases[] =
+  {
+      {"", ""},
+      {"", "a"},
+      {"a", "a"},
+      {"a", "b"},
+      {"foo/bar/baz", "foo/bar/baz/"}
+  };
+  auto TestFn = [](path const& LHS, const directory_entry& LHSE,
+                   path const& RHS, const directory_entry& RHSE) {
+    assert((LHS == RHS) == (LHSE == RHSE));
+    assert((LHS != RHS) == (LHSE != RHSE));
+    assert((LHS < RHS) ==  (LHSE < RHSE));
+    assert((LHS <= RHS) == (LHSE <= RHSE));
+    assert((LHS > RHS) ==  (LHSE > RHSE));
+    assert((LHS >= RHS) == (LHSE >= RHSE));
+  };
+  for (auto const& TC : TestCases) {
+    const directory_entry L(TC.first);
+    const directory_entry R(TC.second);
+    TestFn(TC.first,  L, TC.second, R);
+    TestFn(TC.second, R, TC.first, L);
+  }
+}
+
+int main() {
+  test_comparison_signatures();
+  test_comparisons_simple();
+}

+ 89 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/path.pass.cpp

@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+// const path& path() const noexcept;
+// operator const path&() const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+void test_path_method() {
+  using namespace fs;
+  const path p("foo/bar/baz.exe");
+  const path p2("abc");
+  {
+    directory_entry nce;
+    const directory_entry e("");
+    static_assert(std::is_same<decltype(e.path()),  const path&>::value, "");
+    static_assert(std::is_same<decltype(nce.path()), const path&>::value, "");
+    static_assert(noexcept(e.path()) && noexcept(nce.path()), "");
+  }
+  {
+    directory_entry e(p);
+    path const& pref = e.path();
+    assert(pref == p);
+    assert(&pref == &e.path());
+    e.assign(p2);
+    assert(pref == p2);
+    assert(&pref == &e.path());
+  }
+}
+
+void test_path_conversion() {
+  using namespace fs;
+  const path p("foo/bar/baz.exe");
+  const path p2("abc");
+  {
+    directory_entry nce;
+    const directory_entry e("");
+    // Check conversions exist
+    static_assert(std::is_convertible<directory_entry&,        path const&>::value, "");
+    static_assert(std::is_convertible<directory_entry const&,  path const&>::value, "");
+    static_assert(std::is_convertible<directory_entry &&,      path const&>::value, "");
+    static_assert(std::is_convertible<directory_entry const&&, path const&>::value, "");
+    // Not convertible to non-const
+    static_assert(!std::is_convertible<directory_entry&,        path&>::value, "");
+    static_assert(!std::is_convertible<directory_entry const&,  path&>::value, "");
+    static_assert(!std::is_convertible<directory_entry &&,      path&>::value, "");
+    static_assert(!std::is_convertible<directory_entry const&&, path&>::value, "");
+    // conversions are noexcept
+    static_assert(noexcept(e.operator fs::path const&()) &&
+                  noexcept(e.operator fs::path const&()), "");
+  }
+  // const
+  {
+    directory_entry const e(p);
+    path const& pref = e;
+    assert(&pref == &e.path());
+  }
+  // non-const
+  {
+    directory_entry e(p);
+    path const& pref = e;
+    assert(&pref == &e.path());
+
+    e.assign(p2);
+    assert(pref == p2);
+    assert(&pref == &e.path());
+  }
+}
+
+int main() {
+  test_path_method();
+  test_path_conversion();
+}

+ 51 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/status.pass.cpp

@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+// file_status status() const;
+// file_status status(error_code const&) const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "filesystem_test_helper.hpp"
+
+int main()
+{
+  using namespace fs;
+  {
+    const directory_entry e("foo");
+    std::error_code ec;
+    static_assert(std::is_same<decltype(e.status()), file_status>::value, "");
+    static_assert(std::is_same<decltype(e.status(ec)), file_status>::value, "");
+    static_assert(noexcept(e.status()) == false, "");
+    static_assert(noexcept(e.status(ec)) == true, "");
+  }
+  auto TestFn = [](path const& p) {
+    const directory_entry e(p);
+    std::error_code pec, eec;
+    file_status ps = fs::status(p, pec);
+    file_status es = e.status(eec);
+    assert(ps.type() == es.type());
+    assert(ps.permissions() == es.permissions());
+    assert(pec == eec);
+  };
+  {
+    TestFn(StaticEnv::File);
+    TestFn(StaticEnv::Dir);
+    TestFn(StaticEnv::SymlinkToFile);
+    TestFn(StaticEnv::DNE);
+  }
+}

+ 50 - 0
test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/symlink_status.pass.cpp

@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_entry
+
+// file_status symlink_status() const;
+// file_status symlink_status(error_code&) const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "filesystem_test_helper.hpp"
+
+int main() {
+  using namespace fs;
+  {
+    const directory_entry e("foo");
+    std::error_code ec;
+    static_assert(std::is_same<decltype(e.symlink_status()), file_status>::value, "");
+    static_assert(std::is_same<decltype(e.symlink_status(ec)), file_status>::value, "");
+    static_assert(noexcept(e.symlink_status()) == false, "");
+    static_assert(noexcept(e.symlink_status(ec)) == true, "");
+  }
+  auto TestFn = [](path const& p) {
+    const directory_entry e(p);
+    std::error_code pec, eec;
+    file_status ps = fs::symlink_status(p, pec);
+    file_status es = e.symlink_status(eec);
+    assert(ps.type() == es.type());
+    assert(ps.permissions() == es.permissions());
+    assert(pec == eec);
+  };
+  {
+    TestFn(StaticEnv::File);
+    TestFn(StaticEnv::Dir);
+    TestFn(StaticEnv::SymlinkToFile);
+    TestFn(StaticEnv::DNE);
+  }
+}

+ 59 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/copy.pass.cpp

@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator(directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_copy_construct_tests)
+
+TEST_CASE(test_constructor_signature)
+{
+    using D = directory_iterator;
+    static_assert(std::is_copy_constructible<D>::value, "");
+}
+
+TEST_CASE(test_copy_end_iterator)
+{
+    const directory_iterator endIt;
+    directory_iterator it(endIt);
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_copy_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const directory_iterator endIt{};
+
+    const directory_iterator it(testDir);
+    TEST_REQUIRE(it != endIt);
+    const path entry = *it;
+
+    const directory_iterator it2(it);
+    TEST_REQUIRE(it2 == it);
+    TEST_CHECK(*it2 == entry);
+    TEST_CHECK(*it == entry);
+}
+
+TEST_SUITE_END()

+ 98 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/copy_assign.pass.cpp

@@ -0,0 +1,98 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator& operator=(directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_copy_assign_tests)
+
+TEST_CASE(test_assignment_signature)
+{
+    using D = directory_iterator;
+    static_assert(std::is_copy_assignable<D>::value, "");
+}
+
+TEST_CASE(test_copy_to_end_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+
+    const directory_iterator from(testDir);
+    TEST_REQUIRE(from != directory_iterator{});
+    const path entry = *from;
+
+    directory_iterator to{};
+    to = from;
+    TEST_REQUIRE(to == from);
+    TEST_CHECK(*to == entry);
+    TEST_CHECK(*from == entry);
+}
+
+
+TEST_CASE(test_copy_from_end_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+
+    const directory_iterator from{};
+
+    directory_iterator to(testDir);
+    TEST_REQUIRE(to != directory_iterator{});
+
+    to = from;
+    TEST_REQUIRE(to == from);
+    TEST_CHECK(to == directory_iterator{});
+}
+
+TEST_CASE(test_copy_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const directory_iterator endIt{};
+
+    directory_iterator it_obj(testDir);
+    const directory_iterator& it = it_obj;
+    TEST_REQUIRE(it != endIt);
+    ++it_obj;
+    TEST_REQUIRE(it != endIt);
+    const path entry = *it;
+
+    directory_iterator it2(testDir);
+    TEST_REQUIRE(it2 != it);
+    const path entry2 = *it2;
+    TEST_CHECK(entry2 != entry);
+
+    it2 = it;
+    TEST_REQUIRE(it2 == it);
+    TEST_CHECK(*it2 == entry);
+}
+
+TEST_CASE(test_returns_reference_to_self)
+{
+    const directory_iterator it;
+    directory_iterator it2;
+    directory_iterator& ref = (it2 = it);
+    TEST_CHECK(&ref == &it2);
+}
+
+
+TEST_SUITE_END()

+ 246 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/ctor.pass.cpp

@@ -0,0 +1,246 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// explicit directory_iterator(const path& p);
+// directory_iterator(const path& p, directory_options options);
+// directory_iterator(const path& p, error_code& ec) noexcept;
+// directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_constructor_tests)
+
+TEST_CASE(test_constructor_signatures)
+{
+    using D = directory_iterator;
+
+    // explicit directory_iterator(path const&);
+    static_assert(!std::is_convertible<path, D>::value, "");
+    static_assert(std::is_constructible<D, path>::value, "");
+    static_assert(!std::is_nothrow_constructible<D, path>::value, "");
+
+    // directory_iterator(path const&, error_code&) noexcept
+    static_assert(std::is_nothrow_constructible<D, path, std::error_code&>::value, "");
+
+    // directory_iterator(path const&, directory_options);
+    static_assert(std::is_constructible<D, path, directory_options>::value, "");
+    static_assert(!std::is_nothrow_constructible<D, path, directory_options>::value, "");
+
+    // directory_iterator(path const&, directory_options, error_code&) noexcept
+    static_assert(std::is_nothrow_constructible<D, path, directory_options, std::error_code&>::value, "");
+}
+
+TEST_CASE(test_construction_from_bad_path)
+{
+    std::error_code ec;
+    directory_options opts = directory_options::none;
+    const directory_iterator endIt;
+
+    const path testPaths[] = { StaticEnv::DNE, StaticEnv::BadSymlink };
+    for (path const& testPath : testPaths)
+    {
+        {
+            directory_iterator it(testPath, ec);
+            TEST_CHECK(ec);
+            TEST_CHECK(it == endIt);
+        }
+        {
+            directory_iterator it(testPath, opts, ec);
+            TEST_CHECK(ec);
+            TEST_CHECK(it == endIt);
+        }
+        {
+            TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath));
+            TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath, opts));
+        }
+    }
+}
+
+TEST_CASE(access_denied_test_case)
+{
+    using namespace std::experimental::filesystem;
+    scoped_test_env env;
+    path const testDir = env.make_env_path("dir1");
+    path const testFile = testDir / "testFile";
+    env.create_dir(testDir);
+    env.create_file(testFile, 42);
+
+    // Test that we can iterator over the directory before changing the perms
+    directory_iterator it(testDir);
+    TEST_REQUIRE(it != directory_iterator{});
+
+    // Change the permissions so we can no longer iterate
+    permissions(testDir, perms::none);
+
+    // Check that the construction fails when skip_permissions_denied is
+    // not given.
+    {
+        std::error_code ec;
+        directory_iterator it(testDir, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == directory_iterator{});
+    }
+    // Check that construction does not report an error when
+    // 'skip_permissions_denied' is given.
+    {
+        std::error_code ec;
+        directory_iterator it(testDir, directory_options::skip_permission_denied, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it == directory_iterator{});
+    }
+}
+
+
+TEST_CASE(access_denied_to_file_test_case)
+{
+    using namespace std::experimental::filesystem;
+    scoped_test_env env;
+    path const testFile = env.make_env_path("file1");
+    env.create_file(testFile, 42);
+
+    // Change the permissions so we can no longer iterate
+    permissions(testFile, perms::none);
+
+    // Check that the construction fails when skip_permissions_denied is
+    // not given.
+    {
+        std::error_code ec;
+        directory_iterator it(testFile, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == directory_iterator{});
+    }
+    // Check that construction still fails when 'skip_permissions_denied' is given
+    // because we tried to open a file and not a directory.
+    {
+        std::error_code ec;
+        directory_iterator it(testFile, directory_options::skip_permission_denied, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == directory_iterator{});
+    }
+}
+
+TEST_CASE(test_open_on_empty_directory_equals_end)
+{
+    scoped_test_env env;
+    const path testDir = env.make_env_path("dir1");
+    env.create_dir(testDir);
+
+    const directory_iterator endIt;
+    {
+        std::error_code ec;
+        directory_iterator it(testDir, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(it == endIt);
+    }
+    {
+        directory_iterator it(testDir);
+        TEST_CHECK(it == endIt);
+    }
+}
+
+TEST_CASE(test_open_on_directory_succeeds)
+{
+    const path testDir = StaticEnv::Dir;
+    std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                std::end(  StaticEnv::DirIterationList));
+    const directory_iterator endIt{};
+
+    {
+        std::error_code ec;
+        directory_iterator it(testDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it != endIt);
+        TEST_CHECK(dir_contents.count(*it));
+    }
+    {
+        directory_iterator it(testDir);
+        TEST_CHECK(it != endIt);
+        TEST_CHECK(dir_contents.count(*it));
+    }
+}
+
+TEST_CASE(test_open_on_file_fails)
+{
+    const path testFile = StaticEnv::File;
+    const directory_iterator endIt{};
+    {
+        std::error_code ec;
+        directory_iterator it(testFile, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == endIt);
+    }
+    {
+        TEST_CHECK_THROW(filesystem_error, directory_iterator(testFile));
+    }
+}
+
+TEST_CASE(test_open_on_empty_string)
+{
+    const path testPath = "";
+    const directory_iterator endIt{};
+
+    std::error_code ec;
+    directory_iterator it(testPath, ec);
+    TEST_CHECK(ec);
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_open_on_dot_dir)
+{
+    const path testPath = ".";
+
+    std::error_code ec;
+    directory_iterator it(testPath, ec);
+    TEST_CHECK(!ec);
+}
+
+TEST_CASE(test_open_on_symlink)
+{
+    const path symlinkToDir = StaticEnv::SymlinkToDir;
+    std::set<path> dir_contents;
+    for (path const& p : StaticEnv::DirIterationList) {
+        dir_contents.insert(p.filename());
+    }
+    const directory_iterator endIt{};
+
+    {
+        std::error_code ec;
+        directory_iterator it(symlinkToDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it != endIt);
+        path const& entry = *it;
+        TEST_CHECK(dir_contents.count(entry.filename()));
+    }
+    {
+        std::error_code ec;
+        directory_iterator it(symlinkToDir,
+                              directory_options::follow_directory_symlink, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it != endIt);
+        path const& entry = *it;
+        TEST_CHECK(dir_contents.count(entry.filename()));
+    }
+}
+
+TEST_SUITE_END()

+ 36 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/default_ctor.pass.cpp

@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator::directory_iterator() noexcept
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+    {
+        static_assert(std::is_nothrow_default_constructible<fs::directory_iterator>::value, "");
+    }
+    {
+        fs::directory_iterator d1;
+        const fs::directory_iterator d2;
+        assert(d1 == d2);
+    }
+}

+ 117 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/increment.pass.cpp

@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator& operator++();
+// directory_iterator& increment(error_code& ec) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_increment_tests)
+
+TEST_CASE(test_increment_signatures)
+{
+    using D = directory_iterator;
+    directory_iterator d; ((void)d);
+    std::error_code ec; ((void)ec);
+
+    ASSERT_SAME_TYPE(decltype(++d), directory_iterator&);
+    ASSERT_NOT_NOEXCEPT(++d);
+
+    ASSERT_SAME_TYPE(decltype(d.increment(ec)), directory_iterator&);
+    ASSERT_NOEXCEPT(d.increment(ec));
+}
+
+TEST_CASE(test_prefix_increment)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                      std::end(  StaticEnv::DirIterationList));
+    const directory_iterator endIt{};
+
+    std::error_code ec;
+    directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        directory_iterator& it_ref = ++it;
+        TEST_CHECK(&it_ref == &it);
+    }
+
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_postfix_increment)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                      std::end(  StaticEnv::DirIterationList));
+    const directory_iterator endIt{};
+
+    std::error_code ec;
+    directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        const path entry2 = *it++;
+        TEST_CHECK(entry2 == entry);
+    }
+
+    TEST_CHECK(it == endIt);
+}
+
+
+TEST_CASE(test_increment_method)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                      std::end(  StaticEnv::DirIterationList));
+    const directory_iterator endIt{};
+
+    std::error_code ec;
+    directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        directory_iterator& it_ref = it.increment(ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(&it_ref == &it);
+    }
+
+    TEST_CHECK(it == endIt);
+}
+
+TEST_SUITE_END()

+ 62 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/move.pass.cpp

@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator(directory_iterator&&) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_move_construct_tests)
+
+TEST_CASE(test_constructor_signature)
+{
+    using D = directory_iterator;
+    static_assert(std::is_nothrow_move_constructible<D>::value, "");
+}
+
+TEST_CASE(test_move_end_iterator)
+{
+    const directory_iterator endIt;
+    directory_iterator endIt2{};
+
+    directory_iterator it(std::move(endIt2));
+    TEST_CHECK(it == endIt);
+    TEST_CHECK(endIt2 == endIt);
+}
+
+TEST_CASE(test_move_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const directory_iterator endIt{};
+
+    directory_iterator it(testDir);
+    TEST_REQUIRE(it != endIt);
+    const path entry = *it;
+
+    const directory_iterator it2(std::move(it));
+    TEST_CHECK(*it2 == entry);
+
+    TEST_CHECK(it == it2 || it == endIt);
+}
+
+TEST_SUITE_END()

+ 110 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.members/move_assign.pass.cpp

@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator& operator=(directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_move_assign_tests)
+
+TEST_CASE(test_assignment_signature)
+{
+    using D = directory_iterator;
+    static_assert(std::is_nothrow_move_assignable<D>::value, "");
+}
+
+TEST_CASE(test_move_to_end_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+
+    directory_iterator from(testDir);
+    TEST_REQUIRE(from != directory_iterator{});
+    const path entry = *from;
+
+    directory_iterator to{};
+    to = std::move(from);
+    TEST_REQUIRE(to != directory_iterator{});
+    TEST_CHECK(*to == entry);
+}
+
+
+TEST_CASE(test_move_from_end_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+
+    directory_iterator from{};
+
+    directory_iterator to(testDir);
+    TEST_REQUIRE(to != from);
+
+    to = std::move(from);
+    TEST_REQUIRE(to == directory_iterator{});
+    TEST_REQUIRE(from == directory_iterator{});
+}
+
+TEST_CASE(test_move_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const directory_iterator endIt{};
+
+    directory_iterator it(testDir);
+    TEST_REQUIRE(it != endIt);
+    ++it;
+    TEST_REQUIRE(it != endIt);
+    const path entry = *it;
+
+    directory_iterator it2(testDir);
+    TEST_REQUIRE(it2 != it);
+    const path entry2 = *it2;
+    TEST_CHECK(entry2 != entry);
+
+    it2 = std::move(it);
+    TEST_REQUIRE(it2 != directory_iterator{});
+    TEST_CHECK(*it2 == entry);
+}
+
+TEST_CASE(test_returns_reference_to_self)
+{
+    directory_iterator it;
+    directory_iterator it2;
+    directory_iterator& ref = (it2 = it);
+    TEST_CHECK(&ref == &it2);
+}
+
+
+TEST_CASE(test_self_move)
+{
+    // Create two non-equal iterators that have exactly the same state.
+    directory_iterator it(StaticEnv::Dir);
+    directory_iterator it2(StaticEnv::Dir);
+    ++it; ++it2;
+    TEST_CHECK(it != it2);
+    TEST_CHECK(*it2 == *it);
+
+    it = std::move(it);
+    TEST_CHECK(*it2 == *it);
+}
+
+
+TEST_SUITE_END()

+ 61 - 0
test/std/experimental/filesystem/class.directory_iterator/directory_iterator.nonmembers/begin_end.pass.cpp

@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// directory_iterator begin(directory_iterator iter) noexcept;
+// directory_iterator end(directory_iterator iter) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(directory_iterator_begin_end_tests)
+
+TEST_CASE(test_function_signatures)
+{
+    using D = directory_iterator;
+    directory_iterator d; ((void)d);
+
+    ASSERT_SAME_TYPE(decltype(begin(d)), directory_iterator);
+    ASSERT_NOEXCEPT(begin(std::move(d)));
+
+    ASSERT_SAME_TYPE(decltype(end(d)), directory_iterator);
+    ASSERT_NOEXCEPT(end(std::move(d)));
+}
+
+TEST_CASE(test_ranged_for_loop)
+{
+    const path testDir = StaticEnv::Dir;
+    std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                      std::end(  StaticEnv::DirIterationList));
+
+    std::error_code ec;
+    directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    for (auto& elem : it) {
+        TEST_CHECK(dir_contents.erase(elem) == 1);
+    }
+    TEST_CHECK(dir_contents.empty());
+}
+
+TEST_SUITE_END()

+ 38 - 0
test/std/experimental/filesystem/class.directory_iterator/types.pass.cpp

@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+// typedef ... value_type;
+// typedef ... difference_type;
+// typedef ... pointer;
+// typedef ... reference;
+// typedef ... iterator_category
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+    using namespace fs;
+    using D = directory_iterator;
+    ASSERT_SAME_TYPE(D::value_type, directory_entry);
+    ASSERT_SAME_TYPE(D::difference_type, std::ptrdiff_t);
+    ASSERT_SAME_TYPE(D::pointer, const directory_entry*);
+    ASSERT_SAME_TYPE(D::reference, const directory_entry&);
+    ASSERT_SAME_TYPE(D::iterator_category, std::input_iterator_tag);
+}

+ 61 - 0
test/std/experimental/filesystem/class.file_status/file_status.cons.pass.cpp

@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class file_status
+
+// explicit file_status() noexcept;
+// explicit file_status(file_type, perms prms = perms::unknown) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_convertible.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+ using namespace fs;
+  // Default ctor
+  {
+    static_assert(std::is_nothrow_default_constructible<file_status>::value,
+                  "The default constructor must be noexcept");
+    static_assert(!test_convertible<file_status>(),
+                  "The default constructor must be explicit");
+    const file_status f;
+    assert(f.type()  == file_type::none);
+    assert(f.permissions() == perms::unknown);
+  }
+
+  // Unary ctor
+  {
+    static_assert(std::is_nothrow_constructible<file_status, file_type>::value,
+                  "This constructor must be noexcept");
+    static_assert(!test_convertible<file_status, file_type>(),
+                 "This constructor must be explicit");
+
+    const file_status f(file_type::not_found);
+    assert(f.type()  == file_type::not_found);
+    assert(f.permissions() == perms::unknown);
+  }
+  // Binary ctor
+  {
+    static_assert(std::is_nothrow_constructible<file_status, file_type, perms>::value,
+                  "This constructor must be noexcept");
+    static_assert(!test_convertible<file_status, file_type, perms>(),
+                  "This constructor must b explicit");
+    const file_status f(file_type::regular, perms::owner_read);
+    assert(f.type()  == file_type::regular);
+    assert(f.permissions() == perms::owner_read);
+  }
+}

+ 50 - 0
test/std/experimental/filesystem/class.file_status/file_status.mods.pass.cpp

@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class file_status
+
+// void type(file_type) noexcept;
+// void permissions(perms) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+
+  file_status st;
+
+  // type test
+  {
+    static_assert(noexcept(st.type(file_type::regular)),
+                  "operation must be noexcept");
+    static_assert(std::is_same<decltype(st.type(file_type::regular)), void>::value,
+                 "operation must return void");
+    assert(st.type() != file_type::regular);
+    st.type(file_type::regular);
+    assert(st.type() == file_type::regular);
+  }
+  // permissions test
+  {
+    static_assert(noexcept(st.permissions(perms::owner_read)),
+                  "operation must be noexcept");
+    static_assert(std::is_same<decltype(st.permissions(perms::owner_read)), void>::value,
+                 "operation must return void");
+    assert(st.permissions() != perms::owner_read);
+    st.permissions(perms::owner_read);
+    assert(st.permissions() == perms::owner_read);
+  }
+}

+ 46 - 0
test/std/experimental/filesystem/class.file_status/file_status.obs.pass.cpp

@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class file_status
+
+// file_type type() const noexcept;
+// perms permissions(p) const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+
+  const file_status st(file_type::regular, perms::owner_read);
+
+  // type test
+  {
+    static_assert(noexcept(st.type()),
+                  "operation must be noexcept");
+    static_assert(std::is_same<decltype(st.type()), file_type>::value,
+                 "operation must return file_type");
+    assert(st.type() == file_type::regular);
+  }
+  // permissions test
+  {
+    static_assert(noexcept(st.permissions()),
+                  "operation must be noexcept");
+    static_assert(std::is_same<decltype(st.permissions()), perms>::value,
+                 "operation must return perms");
+    assert(st.permissions() == perms::owner_read);
+  }
+}

+ 103 - 0
test/std/experimental/filesystem/class.filesystem_error/filesystem_error.members.pass.cpp

@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class filesystem_error
+
+// filesystem_error(const string& what_arg, error_code ec);
+// filesystem_error(const string& what_arg, const path& p1, error_code ec);
+// filesystem_error(const string& what_arg, const path& p1, const path& p2, error_code ec);
+// const std::error_code& code() const;
+// const char* what() const noexcept;
+// const path& path1() const noexcept;
+// const path& path2() const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+void test_constructors() {
+  using namespace fs;
+
+  // The string returned by "filesystem_error::what() must contain runtime_error::what()
+  const std::string what_arg = "Hello World";
+  const std::string what_contains = std::runtime_error(what_arg).what();
+  assert(what_contains.find(what_arg) != std::string::npos);
+  auto CheckWhat = [what_contains](filesystem_error const& e) {
+    std::string s = e.what();
+    assert(s.find(what_contains) != std::string::npos);
+  };
+
+  std::error_code ec = std::make_error_code(std::errc::file_exists);
+  const path p1("foo");
+  const path p2("bar");
+
+  // filesystem_error(const string& what_arg, error_code ec);
+  {
+    ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, ec));
+    filesystem_error e(what_arg, ec);
+    CheckWhat(e);
+    assert(e.code() == ec);
+    assert(e.path1().empty() && e.path2().empty());
+  }
+  // filesystem_error(const string& what_arg, const path&, error_code ec);
+  {
+    ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, ec));
+    filesystem_error e(what_arg, p1, ec);
+    CheckWhat(e);
+    assert(e.code() == ec);
+    assert(e.path1() == p1);
+    assert(e.path2().empty());
+  }
+  // filesystem_error(const string& what_arg, const path&, const path&, error_code ec);
+  {
+    ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, p2, ec));
+    filesystem_error e(what_arg, p1, p2, ec);
+    CheckWhat(e);
+    assert(e.code() == ec);
+    assert(e.path1() == p1);
+    assert(e.path2() == p2);
+  }
+}
+
+void test_signatures()
+{
+  using namespace fs;
+  const path p;
+  std::error_code ec;
+  const filesystem_error e("lala", ec);
+  // const path& path1() const noexcept;
+  {
+    ASSERT_SAME_TYPE(path const&, decltype(e.path1()));
+    ASSERT_NOEXCEPT(e.path1());
+  }
+  // const path& path2() const noexcept
+  {
+    ASSERT_SAME_TYPE(path const&, decltype(e.path2()));
+    ASSERT_NOEXCEPT(e.path2());
+  }
+  // const char* what() const noexcept
+  {
+    ASSERT_SAME_TYPE(const char*, decltype(e.what()));
+    ASSERT_NOEXCEPT(e.what());
+  }
+}
+
+int main() {
+  static_assert(std::is_base_of<std::system_error, fs::filesystem_error>::value, "");
+  test_constructors();
+  test_signatures();
+}

+ 104 - 0
test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp

@@ -0,0 +1,104 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class Source>
+//      path(const Source& source);
+// template <class InputIterator>
+//      path(InputIterator first, InputIterator last);
+
+
+#include <experimental/filesystem>
+#include <iterator>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+
+template <class It>
+std::reverse_iterator<It> mkRev(It it) {
+  return std::reverse_iterator<It>(it);
+}
+
+
+void checkIteratorConcepts() {
+  using namespace fs;
+  using It = path::iterator;
+  using Traits = std::iterator_traits<It>;
+  ASSERT_SAME_TYPE(Traits::iterator_category, std::bidirectional_iterator_tag);
+  ASSERT_SAME_TYPE(Traits::value_type, path);
+  ASSERT_SAME_TYPE(Traits::pointer,   path const*);
+  ASSERT_SAME_TYPE(Traits::reference, path const&);
+  {
+    It it;
+    ASSERT_SAME_TYPE(It&, decltype(++it));
+    ASSERT_SAME_TYPE(It, decltype(it++));
+    ASSERT_SAME_TYPE(It&, decltype(--it));
+    ASSERT_SAME_TYPE(It, decltype(it--));
+    ASSERT_SAME_TYPE(Traits::reference, decltype(*it));
+    ASSERT_SAME_TYPE(Traits::pointer, decltype(it.operator->()));
+    ASSERT_SAME_TYPE(std::string const&, decltype(it->native()));
+    ASSERT_SAME_TYPE(bool, decltype(it == it));
+    ASSERT_SAME_TYPE(bool, decltype(it != it));
+  }
+  {
+    path const p;
+    ASSERT_SAME_TYPE(It, decltype(p.begin()));
+    ASSERT_SAME_TYPE(It, decltype(p.end()));
+    assert(p.begin() == p.end());
+  }
+}
+
+void checkBeginEndBasic() {
+  using namespace fs;
+  using It = path::iterator;
+  {
+    path const p;
+    ASSERT_SAME_TYPE(It, decltype(p.begin()));
+    ASSERT_SAME_TYPE(It, decltype(p.end()));
+    assert(p.begin() == p.end());
+  }
+  {
+    path const p("foo");
+    It default_constructed;
+    default_constructed = p.begin();
+    assert(default_constructed == p.begin());
+    assert(default_constructed != p.end());
+    default_constructed = p.end();
+    assert(default_constructed == p.end());
+    assert(default_constructed != p.begin());
+  }
+  {
+    path p("//root_name//first_dir////second_dir");
+    const path expect[] = {"//root_name", "/", "first_dir", "second_dir"};
+    assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+    assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(expect))));
+  }
+  {
+    path p("////foo/bar/baz///");
+    const path expect[] = {"/", "foo", "bar", "baz", "."};
+    assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect)));
+    assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(expect))));
+  }
+}
+
+int main() {
+  using namespace fs;
+  checkIteratorConcepts();
+  checkBeginEndBasic(); // See path.decompose.pass.cpp for more tests.
+}

+ 241 - 0
test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp

@@ -0,0 +1,241 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& operator/=(path const&)
+// template <class Source>
+//      path& operator/=(Source const&);
+// template <class Source>
+//      path& append(Source const&);
+// template <class InputIterator>
+//      path& append(InputIterator first, InputIterator last);
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct AppendOperatorTestcase {
+  MultiStringType lhs;
+  MultiStringType rhs;
+  MultiStringType expect;
+};
+
+#define S(Str) MKSTR(Str)
+const AppendOperatorTestcase Cases[] =
+    {
+        {S(""),     S(""),      S("")}
+      , {S("p1"),   S("p2"),    S("p1/p2")}
+      , {S("p1/"),  S("p2"),    S("p1/p2")}
+      , {S("p1"),   S("/p2"),   S("p1/p2")}
+      , {S("p1/"),  S("/p2"),   S("p1//p2")}
+      , {S("p1"),   S("\\p2"),  S("p1/\\p2")}
+      , {S("p1\\"), S("p2"),  S("p1\\/p2")}
+      , {S("p1\\"), S("\\p2"),  S("p1\\/\\p2")}
+      , {S("p1"),   S(""),      S("p1")}
+      , {S(""),     S("p2"),    S("p2")}
+    };
+
+
+const AppendOperatorTestcase LongLHSCases[] =
+    {
+        {S("p1"),   S("p2"),    S("p1/p2")}
+      , {S("p1/"),  S("p2"),    S("p1/p2")}
+      , {S("p1"),   S("/p2"),   S("p1/p2")}
+    };
+#undef S
+
+
+// The append operator may need to allocate a temporary buffer before a code_cvt
+// conversion. Test if this allocation occurs by:
+//   1. Create a path, `LHS`, and reserve enough space to append `RHS`.
+//      This prevents `LHS` from allocating during the actual appending.
+//   2. Create a `Source` object `RHS`, which represents a "large" string.
+//      (The string must not trigger the SSO)
+//   3. Append `RHS` to `LHS` and check for the expected allocation behavior.
+template <class CharT>
+void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
+{
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  using InputIter = input_iterator<Ptr>;
+
+  const Ptr L = TC.lhs;
+  Str RShort = (Ptr)TC.rhs;
+  Str EShort = (Ptr)TC.expect;
+  assert(RShort.size() >= 2);
+  CharT c = RShort.back();
+  RShort.append(100, c);
+  EShort.append(100, c);
+  const Ptr R = RShort.data();
+  const Str& E = EShort;
+  std::size_t ReserveSize = E.size() + 3;
+  // basic_string
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Str  RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS /= RHS;
+    }
+    assert(LHS == E);
+  }
+  // CharT*
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Ptr RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS /= RHS;
+    }
+    assert(LHS == E);
+  }
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Ptr RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS.append(RHS, StrEnd(RHS));
+    }
+    assert(LHS == E);
+  }
+  // input iterator - For non-native char types, appends needs to copy the
+  // iterator range into a contigious block of memory before it can perform the
+  // code_cvt conversions.
+  // For "char" no allocations will be performed because no conversion is
+  // required.
+  bool DisableAllocations = std::is_same<CharT, char>::value;
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    InputIter RHS(R);
+    {
+      RequireAllocationGuard  g; // requires 1 or more allocations occur by default
+      if (DisableAllocations) g.requireExactly(0);
+      LHS /= RHS;
+    }
+    assert(LHS == E);
+  }
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    InputIter RHS(R);
+    InputIter REnd(StrEnd(R));
+    {
+      RequireAllocationGuard g;
+      if (DisableAllocations) g.requireExactly(0);
+      LHS.append(RHS, REnd);
+    }
+    assert(LHS == E);
+  }
+}
+
+template <class CharT>
+void doAppendSourceTest(AppendOperatorTestcase const& TC)
+{
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  using InputIter = input_iterator<Ptr>;
+  const Ptr L = TC.lhs;
+  const Ptr R = TC.rhs;
+  const Ptr E = TC.expect;
+  // basic_string
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = (LHS /= RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = LHS.append(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  // Char*
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = (LHS /= RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Ptr RHS(R);
+    path& Ref = LHS.append(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Ptr RHS(R);
+    path& Ref = LHS.append(RHS, StrEnd(RHS));
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  // iterators
+  {
+    path LHS(L);
+    InputIter RHS(R);
+    path& Ref = (LHS /= RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L); InputIter RHS(R);
+    path& Ref = LHS.append(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    InputIter RHS(R);
+    InputIter REnd(StrEnd(R));
+    path& Ref = LHS.append(RHS, REnd);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+}
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : Cases) {
+    {
+      path LHS((const char*)TC.lhs);
+      path RHS((const char*)TC.rhs);
+      path& Ref = (LHS /= RHS);
+      assert(LHS == (const char*)TC.expect);
+      assert(&Ref == &LHS);
+    }
+    doAppendSourceTest<char>    (TC);
+    doAppendSourceTest<wchar_t> (TC);
+    doAppendSourceTest<char16_t>(TC);
+    doAppendSourceTest<char32_t>(TC);
+  }
+  for (auto const & TC : LongLHSCases) {
+    doAppendSourceAllocTest<char>(TC);
+    doAppendSourceAllocTest<wchar_t>(TC);
+  }
+}

+ 37 - 0
test/std/experimental/filesystem/class.path/path.member/path.assign/copy.pass.cpp

@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& operator=(path const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  static_assert(std::is_copy_assignable<path>::value, "");
+  static_assert(!std::is_nothrow_copy_assignable<path>::value, "should not be noexcept");
+  const std::string s("foo");
+  const path p(s);
+  path p2;
+  path& pref = (p2 = p);
+  assert(p.native() == s);
+  assert(p2.native() == s);
+  assert(&pref == &p2);
+}

+ 43 - 0
test/std/experimental/filesystem/class.path/path.member/path.assign/move.pass.cpp

@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& operator=(path&&) noexcept
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  static_assert(std::is_nothrow_move_assignable<path>::value, "");
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  const std::string s("we really really really really really really really "
+                      "really really long string so that we allocate");
+  assert(globalMemCounter.checkOutstandingNewEq(1));
+  path p(s);
+  {
+    DisableAllocationGuard g;
+    path p2;
+    path& pref = (p2 = std::move(p));
+    assert(p2.native() == s);
+    assert(p.native() != s); // Testing moved from state
+    assert(&pref == &p2);
+  }
+}

+ 153 - 0
test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp

@@ -0,0 +1,153 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class Source>
+//      path& operator=(Source const&);
+// template <class Source>
+//      path& assign(Source const&);
+// template <class InputIterator>
+//      path& assign(InputIterator first, InputIterator last);
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+namespace fs = std::experimental::filesystem;
+
+template <class CharT>
+void RunTestCase(MultiStringType const& MS) {
+  using namespace fs;
+  const char* Expect = MS;
+  const CharT* TestPath = MS;
+  const CharT* TestPathEnd = StrEnd(TestPath);
+  const std::size_t Size = TestPathEnd - TestPath;
+  const std::size_t SSize = StrEnd(Expect) - Expect;
+  assert(Size == SSize);
+  //////////////////////////////////////////////////////////////////////////////
+  // basic_string<Char, Traits, Alloc>
+  {
+    const std::basic_string<CharT> S(TestPath);
+    path p; PathReserve(p, S.length() + 1);
+    {
+      // string provides a contigious iterator. No allocation needed.
+      DisableAllocationGuard g;
+      path& pref = (p = S);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+    assert(p.string<CharT>() == S);
+  }
+  {
+    const std::basic_string<CharT> S(TestPath);
+    path p; PathReserve(p, S.length() + 1);
+    {
+      DisableAllocationGuard g;
+      path& pref = p.assign(S);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+    assert(p.string<CharT>() == S);
+  }
+  //////////////////////////////////////////////////////////////////////////////
+  // Char* pointers
+  {
+    path p; PathReserve(p, Size + 1);
+    {
+      // char* pointers are contigious and can be used with code_cvt directly.
+      // no allocations needed.
+      DisableAllocationGuard g;
+      path& pref = (p = TestPath);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    path p; PathReserve(p, Size + 1);
+    {
+      DisableAllocationGuard g;
+      path& pref = p.assign(TestPath);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    path p; PathReserve(p, Size + 1);
+    {
+      DisableAllocationGuard g;
+      path& pref = p.assign(TestPath, TestPathEnd);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  //////////////////////////////////////////////////////////////////////////////
+  // Iterators
+  {
+    using It = input_iterator<const CharT*>;
+    path p; PathReserve(p, Size + 1);
+    It it(TestPath);
+    {
+      // Iterators cannot be used with code_cvt directly. This assignment
+      // may allocate if it's larger than a "short-string".
+      path& pref = (p = it);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    using It = input_iterator<const CharT*>;
+    path p; PathReserve(p, Size + 1);
+    It it(TestPath);
+    {
+      path& pref = p.assign(it);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    using It = input_iterator<const CharT*>;
+    path p; PathReserve(p, Size + 1);
+    It it(TestPath);
+    It e(TestPathEnd);
+    {
+      path& pref = p.assign(it, e);
+      assert(&pref == &p);
+    }
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+}
+
+int main() {
+  for (auto const& MS : PathList) {
+    RunTestCase<char>(MS);
+    RunTestCase<wchar_t>(MS);
+    RunTestCase<char16_t>(MS);
+    RunTestCase<char32_t>(MS);
+  }
+}

+ 126 - 0
test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp

@@ -0,0 +1,126 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// int compare(path const&) const noexcept;
+// int compare(string_type const&) const;
+// int compare(value_type const*) const;
+//
+// bool operator==(path const&, path const&) noexcept;
+// bool operator!=(path const&, path const&) noexcept;
+// bool operator< (path const&, path const&) noexcept;
+// bool operator<=(path const&, path const&) noexcept;
+// bool operator> (path const&, path const&) noexcept;
+// bool operator>=(path const&, path const&) noexcept;
+//
+// size_t hash_value(path const&) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <vector>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct PathCompareTest {
+  const char* LHS;
+  const char* RHS;
+  int expect;
+};
+
+#define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+#define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+#define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
+#define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
+const PathCompareTest CompareTestCases[] =
+{
+    {"", "",  0},
+    {"a", "", 1},
+    {"", "a", -1},
+    {"a/b/c", "a/b/c", 0},
+    {"b/a/c", "a/b/c", 1},
+    {"a/b/c", "b/a/c", -1},
+    {"a/b", "a/b/c", -1},
+    {"a/b/c", "a/b", 1},
+    {"a/b/", "a/b/.", 0},
+    {"a/b//////", "a/b/////.", 0},
+    {"a/.././b", "a///..//.////b", 0},
+    {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators
+    {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory
+    {"/foo/bar/", "/foo/bar", 1}, // trailing separator
+    {"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0},
+    { LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1}
+
+};
+#undef LONGA
+#undef LONGB
+#undef LONGC
+#undef LONGD
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : CompareTestCases) {
+    const path p1(TC.LHS);
+    const path p2(TC.RHS);
+    const std::string R(TC.RHS);
+    const int E = TC.expect;
+    { // compare(...) functions
+      DisableAllocationGuard g; // none of these operations should allocate
+
+      // check runtime results
+      int ret1 = p1.compare(p2);
+      int ret2 = p1.compare(R);
+      int ret3 = p1.compare(TC.RHS);
+      assert(ret1 == ret2 && ret1 == ret3);
+      int normalized_ret = ret1 < 0 ? -1 : (ret1 > 0 ? 1 : 0);
+      assert(normalized_ret == E);
+
+      // check signatures
+      ASSERT_NOEXCEPT(p1.compare(p2));
+    }
+    { // comparison operators
+      DisableAllocationGuard g; // none of these operations should allocate
+
+      // Check runtime result
+      assert((p1 == p2) == (E == 0));
+      assert((p1 != p2) == (E != 0));
+      assert((p1 <  p2) == (E <  0));
+      assert((p1 <= p2) == (E <= 0));
+      assert((p1 >  p2) == (E >  0));
+      assert((p1 >= p2) == (E >= 0));
+
+      // Check signatures
+      ASSERT_NOEXCEPT(p1 == p2);
+      ASSERT_NOEXCEPT(p1 != p2);
+      ASSERT_NOEXCEPT(p1 <  p2);
+      ASSERT_NOEXCEPT(p1 <= p2);
+      ASSERT_NOEXCEPT(p1 >  p2);
+      ASSERT_NOEXCEPT(p1 >= p2);
+    }
+    { // check hash values
+      auto h1 = hash_value(p1);
+      auto h2 = hash_value(p2);
+      assert((h1 == h2) == (p1 == p2));
+      // check signature
+      ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1)));
+      ASSERT_NOEXCEPT(hash_value(p1));
+    }
+  }
+}

+ 277 - 0
test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp

@@ -0,0 +1,277 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& operator+=(const path& x);
+// path& operator+=(const string_type& x); // Implemented as Source template
+// path& operator+=(const value_type* x);  // Implemented as Source template
+// path& operator+=(value_type x);
+// template <class Source>
+//   path& operator+=(const Source& x);
+// template <class EcharT>
+//   path& operator+=(EcharT x);
+// template <class Source>
+//   path& concat(const Source& x);
+// template <class InputIterator>
+//   path& concat(InputIterator first, InputIterator last);
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct ConcatOperatorTestcase {
+  MultiStringType lhs;
+  MultiStringType rhs;
+  MultiStringType expect;
+};
+
+#define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"
+#define S(Str) MKSTR(Str)
+const ConcatOperatorTestcase Cases[] =
+    {
+        {S(""),         S(""),                  S("")}
+      , {S("p1"),       S("p2"),                S("p1p2")}
+      , {S("p1/"),      S("/p2"),               S("p1//p2")}
+      , {S(""),         S("\\foo/bar/baz"),     S("\\foo/bar/baz")}
+      , {S("c:\\foo"),  S(""),                  S("c:\\foo")}
+      , {S(LONGSTR),    S("foo"),               S(LONGSTR "foo")}
+      , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}
+    };
+const ConcatOperatorTestcase LongLHSCases[] =
+    {
+        {S(""),        S(LONGSTR),     S(LONGSTR)}
+      , {S("p1/"),     S(LONGSTR),      S("p1/" LONGSTR)}
+    };
+const ConcatOperatorTestcase CharTestCases[] =
+    {
+        {S(""),       S("P"), S("P")}
+      , {S("/fooba"), S("r"), S("/foobar")}
+    };
+#undef S
+#undef LONGSTR
+
+// The concat operator may need to allocate a temporary buffer before a code_cvt
+// conversion. Test if this allocation occurs by:
+//   1. Create a path, `LHS`, and reserve enough space to append `RHS`.
+//      This prevents `LHS` from allocating during the actual appending.
+//   2. Create a `Source` object `RHS`, which represents a "large" string.
+//      (The string must not trigger the SSO)
+//   3. Concat `RHS` to `LHS` and check for the expected allocation behavior.
+template <class CharT>
+void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
+{
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  using InputIter = input_iterator<Ptr>;
+
+  const Ptr L = TC.lhs;
+  const Ptr R = TC.rhs;
+  const Ptr E =  TC.expect;
+  std::size_t ReserveSize = StrLen(E) + 1;
+  // basic_string
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Str  RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS += RHS;
+    }
+    assert(LHS == E);
+  }
+  // CharT*
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Ptr RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS += RHS;
+    }
+    assert(LHS == E);
+  }
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    Ptr RHS(R);
+    {
+      DisableAllocationGuard g;
+      LHS.concat(RHS, StrEnd(RHS));
+    }
+    assert(LHS == E);
+  }
+  // input iterator - For non-native char types, appends needs to copy the
+  // iterator range into a contigious block of memory before it can perform the
+  // code_cvt conversions.
+  // For "char" no allocations will be performed because no conversion is
+  // required.
+  bool DisableAllocations = std::is_same<CharT, char>::value;
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    InputIter RHS(R);
+    {
+      RequireAllocationGuard  g; // requires 1 or more allocations occur by default
+      if (DisableAllocations) g.requireExactly(0);
+      LHS += RHS;
+    }
+    assert(LHS == E);
+  }
+  {
+    path LHS(L); PathReserve(LHS, ReserveSize);
+    InputIter RHS(R);
+    InputIter REnd(StrEnd(R));
+    {
+      RequireAllocationGuard g;
+      if (DisableAllocations) g.requireExactly(0);
+      LHS.concat(RHS, REnd);
+    }
+    assert(LHS == E);
+  }
+}
+
+template <class CharT>
+void doConcatSourceTest(ConcatOperatorTestcase const& TC)
+{
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  using InputIter = input_iterator<Ptr>;
+  const Ptr L = TC.lhs;
+  const Ptr R = TC.rhs;
+  const Ptr E = TC.expect;
+  // basic_string
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = (LHS += RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = LHS.concat(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  // Char*
+  {
+    path LHS(L);
+    Str RHS(R);
+    path& Ref = (LHS += RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Ptr RHS(R);
+    path& Ref = LHS.concat(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    Ptr RHS(R);
+    path& Ref = LHS.concat(RHS, StrEnd(RHS));
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  // iterators
+  {
+    path LHS(L);
+    InputIter RHS(R);
+    path& Ref = (LHS += RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L); InputIter RHS(R);
+    path& Ref = LHS.concat(RHS);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+  {
+    path LHS(L);
+    InputIter RHS(R);
+    InputIter REnd(StrEnd(R));
+    path& Ref = LHS.concat(RHS, REnd);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+}
+
+template <class CharT>
+void doConcatECharTest(ConcatOperatorTestcase const& TC)
+{
+  using namespace fs;
+  using Ptr = CharT const*;
+  const Ptr RStr = TC.rhs;
+  assert(StrLen(RStr) == 1);
+  const Ptr L   = TC.lhs;
+  const CharT R = RStr[0];
+  const Ptr E   = TC.expect;
+  {
+    path LHS(L);
+    path& Ref = (LHS += R);
+    assert(LHS == E);
+    assert(&Ref == &LHS);
+  }
+}
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : Cases) {
+    {
+      path LHS((const char*)TC.lhs);
+      path RHS((const char*)TC.rhs);
+      path& Ref = (LHS += RHS);
+      assert(LHS == (const char*)TC.expect);
+      assert(&Ref == &LHS);
+    }
+    doConcatSourceTest<char>    (TC);
+    doConcatSourceTest<wchar_t> (TC);
+    doConcatSourceTest<char16_t>(TC);
+    doConcatSourceTest<char32_t>(TC);
+  }
+  for (auto const & TC : LongLHSCases) {
+    // Do path test
+    {
+      path LHS((const char*)TC.lhs);
+      path RHS((const char*)TC.rhs);
+      const char* E = TC.expect;
+      PathReserve(LHS, StrLen(E) + 5);
+      {
+        DisableAllocationGuard g;
+        path& Ref = (LHS += RHS);
+        assert(&Ref == &LHS);
+      }
+      assert(LHS == E);
+    }
+    doConcatSourceAllocTest<char>(TC);
+    doConcatSourceAllocTest<wchar_t>(TC);
+  }
+  for (auto const& TC : CharTestCases) {
+    doConcatECharTest<char>(TC);
+    doConcatECharTest<wchar_t>(TC);
+    doConcatECharTest<char16_t>(TC);
+    doConcatECharTest<char32_t>(TC);
+  }
+}

+ 35 - 0
test/std/experimental/filesystem/class.path/path.member/path.construct/copy.pass.cpp

@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path(path const&)
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  static_assert(std::is_copy_constructible<path>::value, "");
+  static_assert(!std::is_nothrow_copy_constructible<path>::value, "should not be noexcept");
+  const std::string s("foo");
+  const path p(s);
+  path p2(p);
+  assert(p.native() == s);
+  assert(p2.native() == s);
+}

+ 31 - 0
test/std/experimental/filesystem/class.path/path.member/path.construct/default.pass.cpp

@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path() noexcept
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  static_assert(std::is_nothrow_default_constructible<path>::value, "");
+  const path p;
+  assert(p.empty());
+}

+ 41 - 0
test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp

@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path(path&&) noexcept
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  static_assert(std::is_nothrow_move_constructible<path>::value, "");
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  const std::string s("we really really really really really really really "
+                      "really really long string so that we allocate");
+  assert(globalMemCounter.checkOutstandingNewEq(1));
+  path p(s);
+  {
+    DisableAllocationGuard g;
+    path p2(std::move(p));
+    assert(p2.native() == s);
+    assert(p.native() != s); // Testing moved from state
+  }
+}

+ 83 - 0
test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp

@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class Source>
+//      path(const Source& source);
+// template <class InputIterator>
+//      path(InputIterator first, InputIterator last);
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+template <class CharT>
+void RunTestCase(MultiStringType const& MS) {
+  using namespace fs;
+  const char* Expect = MS;
+  const CharT* TestPath = MS;
+  const CharT* TestPathEnd = StrEnd(TestPath);
+  const std::size_t Size = TestPathEnd - TestPath;
+  const std::size_t SSize = StrEnd(Expect) - Expect;
+  assert(Size == SSize);
+  // StringTypes
+  {
+    const std::basic_string<CharT> S(TestPath);
+    path p(S);
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+    assert(p.string<CharT>() == S);
+  }
+  // Char* pointers
+  {
+    path p(TestPath);
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    path p(TestPath, TestPathEnd);
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  // Iterators
+  {
+    using It = input_iterator<const CharT*>;
+    path p(It{TestPath});
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+  {
+    using It = input_iterator<const CharT*>;
+    path p(It{TestPath}, It{TestPathEnd});
+    assert(p.native() == Expect);
+    assert(p.string<CharT>() == TestPath);
+  }
+}
+
+int main() {
+  for (auto const& MS : PathList) {
+    RunTestCase<char>(MS);
+    RunTestCase<wchar_t>(MS);
+    RunTestCase<char16_t>(MS);
+    RunTestCase<char32_t>(MS);
+  }
+}

+ 198 - 0
test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp

@@ -0,0 +1,198 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// 8.4.9 path decomposition [path.decompose]
+//------------------------------------------
+// path root_name() const;
+// path root_directory() const;
+// path root_path() const;
+// path relative_path() const;
+// path parent_path() const;
+// path filename() const;
+// path stem() const;
+// path extension() const;
+//-------------------------------
+// 8.4.10 path query [path.query]
+//-------------------------------
+// bool empty() const noexcept;
+// bool has_root_path() const;
+// bool has_root_name() const;
+// bool has_root_directory() const;
+// bool has_relative_path() const;
+// bool has_parent_path() const;
+// bool has_filename() const;
+// bool has_stem() const;
+// bool has_extension() const;
+// bool is_absolute() const;
+// bool is_relative() const;
+//-------------------------------
+// 8.5 path iterators [path.itr]
+//-------------------------------
+// iterator begin() const;
+// iterator end() const;
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <vector>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+template <class It>
+std::reverse_iterator<It> mkRev(It it) {
+  return std::reverse_iterator<It>(it);
+}
+
+
+namespace fs = std::experimental::filesystem;
+struct PathDecomposeTestcase
+{
+    std::string raw;
+    std::vector<std::string> elements;
+    std::string root_path;
+    std::string root_name;
+    std::string root_directory;
+    std::string relative_path;
+    std::string parent_path;
+    std::string filename;
+};
+
+const PathDecomposeTestcase PathTestCases[] =
+  {
+      {"", {}, "", "", "", "", "", ""}
+    , {".", {"."}, "", "", "", ".", "", "."}
+    , {"..", {".."}, "", "", "", "..", "", ".."}
+    , {"foo", {"foo"}, "", "", "", "foo", "", "foo"}
+    , {"/", {"/"}, "/", "", "/", "", "", "/"}
+    , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"}
+    , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."}
+    , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."}
+    , {"foo/bar", {"foo","bar"}, "",  "", "",  "foo/bar", "foo", "bar"}
+    , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"}
+    , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"}
+    , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/", "foo", "//net/", "foo"}
+    , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///", "///foo", "."}
+    , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"}
+    , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."}
+    , {"./", {".", "."}, "", "", "", "./", ".", "."}
+    , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."}
+    , {"../", {"..", "."}, "", "", "", "../", "..", "."}
+    , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."}
+    , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."}
+    , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."}
+    , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"}
+    , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..", "."}
+    , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"}
+    , {"c:", {"c:"}, "", "", "", "c:", "", "c:"}
+    , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."}
+    , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"}
+    , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"}
+    , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."}
+    , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/",  "c:/foo", "."}
+    , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"}
+    , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"}
+    , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"}
+    , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"}
+    , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"}
+    , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"}
+    , {"c:\\foo/",  {"c:\\foo", "."}, "", "", "", "c:\\foo/", "c:\\foo", "."}
+    , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"}
+    , {"//", {"//"}, "//", "//", "", "", "", "//"}
+  };
+
+void decompPathTest()
+{
+  using namespace fs;
+  for (auto const & TC : PathTestCases) {
+    path p(TC.raw);
+    assert(p == TC.raw);
+
+    assert(p.root_path() == TC.root_path);
+    assert(p.has_root_path() !=  TC.root_path.empty());
+
+    assert(p.root_name() == TC.root_name);
+    assert(p.has_root_name() !=  TC.root_name.empty());
+
+    assert(p.root_directory() == TC.root_directory);
+    assert(p.has_root_directory() !=  TC.root_directory.empty());
+
+    assert(p.relative_path() == TC.relative_path);
+    assert(p.has_relative_path() !=  TC.relative_path.empty());
+
+    assert(p.parent_path() == TC.parent_path);
+    assert(p.has_parent_path() !=  TC.parent_path.empty());
+
+    assert(p.filename() == TC.filename);
+    assert(p.has_filename() !=  TC.filename.empty());
+
+    assert(p.is_absolute() == p.has_root_directory());
+    assert(p.is_relative() !=  p.is_absolute());
+
+    assert(checkCollectionsEqual(p.begin(), p.end(),
+                                 TC.elements.begin(), TC.elements.end()));
+    // check backwards
+    assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()),
+                                 TC.elements.rbegin(), TC.elements.rend()));
+  }
+}
+
+
+struct FilenameDecompTestcase
+{
+  std::string raw;
+  std::string filename;
+  std::string stem;
+  std::string extension;
+};
+
+const FilenameDecompTestcase FilenameTestCases[] =
+{
+    {"", "", "", ""}
+  , {".", ".", ".", ""}
+  , {"..", "..", "..", ""}
+  , {"/", "/", "/", ""}
+  , {"foo", "foo", "foo", ""}
+  , {"/foo/bar.txt", "bar.txt", "bar", ".txt"}
+  , {"foo..txt", "foo..txt", "foo.", ".txt"}
+};
+
+
+void decompFilenameTest()
+{
+  using namespace fs;
+  for (auto const & TC : FilenameTestCases) {
+    path p(TC.raw);
+    assert(p == TC.raw);
+
+    assert(p.filename() == TC.filename);
+    assert(p.has_filename() != TC.filename.empty());
+
+    assert(p.stem() == TC.stem);
+    assert(p.has_stem() != TC.stem.empty());
+
+    assert(p.extension() == TC.extension);
+    assert(p.has_extension() != TC.extension.empty());
+  }
+}
+
+int main()
+{
+  decompPathTest();
+  decompFilenameTest();
+}

+ 57 - 0
test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp

@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class ECharT, class Traits = char_traits<ECharT>,
+//           class Allocator = allocator<ECharT>>
+// basic_string<ECharT, Traits, Allocator>
+// generic_string(const Allocator& a = Allocator()) const;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+
+// generic_string<C, T, A> forwards to string<C, T, A>. Tests for
+// string<C, T, A>() are in "path.native.op/string_alloc.pass.cpp".
+// generic_string is minimally tested here.
+int main()
+{
+  using namespace fs;
+  using CharT = wchar_t;
+  using Traits = std::char_traits<CharT>;
+  using Alloc = malloc_allocator<CharT>;
+  using Str = std::basic_string<CharT, Traits, Alloc>;
+  const wchar_t* expect = longString;
+  const path p((const char*)longString);
+  {
+    DisableAllocationGuard g;
+    Alloc a;
+    Alloc::disable_default_constructor = true;
+    Str s = p.generic_string<wchar_t, Traits, Alloc>(a);
+    assert(s == expect);
+    assert(Alloc::alloc_count > 0);
+    assert(Alloc::outstanding_alloc() == 1);
+  }
+}

+ 63 - 0
test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp

@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// std::string  generic_string() const;
+// std::wstring generic_wstring() const;
+// std::u8string  generic_u8string() const;
+// std::u16string generic_u16string() const;
+// std::u32string generic_u32string() const;
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+int main()
+{
+  using namespace fs;
+  auto const& MS = longString;
+  const char* value = longString;
+  const path p(value);
+  {
+    std::string s = p.generic_string();
+    assert(s == value);
+  }
+  {
+    std::string s = p.generic_u8string();
+    assert(s == (const char*)MS);
+  }
+  {
+    std::wstring s = p.generic_wstring();
+    assert(s == (const wchar_t*)MS);
+  }
+  {
+    std::u16string s = p.generic_u16string();
+    assert(s == (const char16_t*)MS);
+  }
+  {
+    std::u32string s = p.generic_u32string();
+    assert(s == (const char32_t*)MS);
+  }
+}

+ 45 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/clear.pass.cpp

@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// void clear() noexcept
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  const path p("/foo/bar/baz");
+  {
+    path p;
+    ASSERT_NOEXCEPT(p.clear());
+    ASSERT_SAME_TYPE(void, decltype(p.clear()));
+    p.clear();
+    assert(p.empty());
+  }
+  {
+    path p2(p);
+    assert(p == p2);
+    p2.clear();
+    assert(p2.empty());
+  }
+}

+ 55 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/make_preferred.pass.cpp

@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& make_preferred()
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct MakePreferredTestcase {
+  const char* value;
+};
+
+const MakePreferredTestcase TestCases[] =
+  {
+      {""}
+    , {"hello_world"}
+    , {"/"}
+    , {"/foo/bar/baz/"}
+    , {"\\"}
+    , {"\\foo\\bar\\baz\\"}
+    , {"\\foo\\/bar\\/baz\\"}
+  };
+
+int main()
+{
+  // This operation is an identity operation on linux.
+  using namespace fs;
+  for (auto const & TC : TestCases) {
+    path p(TC.value);
+    assert(p == TC.value);
+    path& Ref = (p.make_preferred());
+    assert(p.native() == TC.value);
+    assert(&Ref == &p);
+  }
+}

+ 72 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp

@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& remove_filename()
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct RemoveFilenameTestcase {
+  const char* value;
+  const char* expect;
+};
+
+const RemoveFilenameTestcase TestCases[] =
+  {
+      {"", ""}
+    , {"/", ""}
+    , {"\\", ""}
+    , {".", ""}
+    , {"..", ""}
+    , {"/foo", "/"}
+    , {"/foo/", "/foo"}
+    , {"/foo/.", "/foo"}
+    , {"/foo/..", "/foo"}
+    , {"/foo/////", "/foo"}
+    , {"/foo\\\\", "/"}
+    , {"/foo//\\/", "/foo//\\"}
+    , {"file.txt", ""}
+    , {"bar/../baz/./file.txt", "bar/../baz/."}
+  };
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : TestCases) {
+    path const p_orig(TC.value);
+    path p(p_orig);
+    assert(p == TC.value);
+    path& Ref = (p.remove_filename());
+    assert(p == TC.expect);
+    assert(&Ref == &p);
+    {
+      const path parentp = p_orig.parent_path();
+      if (parentp == p_orig.root_name()) {
+
+        assert(p.empty());
+      } else {
+        assert(p == parentp);
+      }
+    }
+  }
+}

+ 73 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_extension.pass.cpp

@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& replace_extension(path const& p = path())
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct ReplaceExtensionTestcase {
+  const char* value;
+  const char* expect;
+  const char* extension;
+};
+
+const ReplaceExtensionTestcase TestCases[] =
+  {
+      {"", "", ""}
+    , {"foo.cpp", "foo", ""}
+    , {"foo.cpp", "foo.", "."}
+    , {"foo..cpp", "foo..txt", "txt"}
+    , {"", ".txt", "txt"}
+    , {"", ".txt", ".txt"}
+    , {"/foo", "/foo.txt", ".txt"}
+    , {"/foo", "/foo.txt", "txt"}
+    , {"/foo.cpp", "/foo.txt", ".txt"}
+    , {"/foo.cpp", "/foo.txt", "txt"}
+  };
+const ReplaceExtensionTestcase NoArgCases[] =
+  {
+      {"", ""}
+    , {"foo", "foo"}
+    , {"foo.cpp", "foo"}
+    , {"foo..cpp", "foo."}
+};
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : TestCases) {
+    path p(TC.value);
+    assert(p == TC.value);
+    path& Ref = (p.replace_extension(TC.extension));
+    assert(p == TC.expect);
+    assert(&Ref == &p);
+  }
+  for (auto const& TC : NoArgCases) {
+    path p(TC.value);
+    assert(p == TC.value);
+    path& Ref = (p.replace_extension());
+    assert(p == TC.expect);
+    assert(&Ref == &p);
+  }
+}

+ 69 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp

@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// path& replace_filename()
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct ReplaceFilenameTestcase {
+  const char* value;
+  const char* expect;
+  const char* filename;
+};
+
+const ReplaceFilenameTestcase TestCases[] =
+  {
+      {"/foo", "/bar", "bar"}
+    , {"/foo", "/", ""}
+    , {"foo", "bar", "bar"}
+    , {"/", "bar", "bar"}
+    , {"\\", "bar", "bar"}
+    , {"///", "bar", "bar"}
+    , {"\\\\", "bar", "bar"}
+    , {"\\/\\", "\\/bar", "bar"}
+    , {".", "bar", "bar"}
+    , {"..", "bar", "bar"}
+    , {"/foo\\baz/bong/", "/foo\\baz/bong/bar", "bar"}
+    , {"/foo\\baz/bong", "/foo\\baz/bar", "bar"}
+  };
+
+int main()
+{
+  using namespace fs;
+  for (auto const & TC : TestCases) {
+    path p(TC.value);
+    assert(p == TC.value);
+    path& Ref = (p.replace_filename(TC.filename));
+    assert(p == TC.expect);
+    assert(&Ref == &p);
+    // Tests Effects "as-if": remove_filename() append(filename)
+    {
+      path p2(TC.value);
+      path replace(TC.filename);
+      p2.remove_filename();
+      p2 /= replace;
+      assert(p2 == p);
+    }
+  }
+}

+ 81 - 0
test/std/experimental/filesystem/class.path/path.member/path.modifiers/swap.pass.cpp

@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// void swap(path& rhs) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+struct SwapTestcase {
+  const char* value1;
+  const char* value2;
+};
+
+#define LONG_STR1 "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG"
+#define LONG_STR2 "_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2"
+const SwapTestcase TestCases[] =
+  {
+      {"", ""}
+    , {"shortstr", LONG_STR1}
+    , {LONG_STR1, "shortstr"}
+    , {LONG_STR1, LONG_STR2}
+  };
+#undef LONG_STR1
+#undef LONG_STR2
+
+int main()
+{
+  using namespace fs;
+  {
+    path p;
+    ASSERT_NOEXCEPT(p.swap(p));
+    ASSERT_SAME_TYPE(void, decltype(p.swap(p)));
+  }
+  for (auto const & TC : TestCases) {
+    path p1(TC.value1);
+    path p2(TC.value2);
+    {
+      DisableAllocationGuard g;
+      p1.swap(p2);
+    }
+    assert(p1 == TC.value2);
+    assert(p2 == TC.value1);
+    {
+      DisableAllocationGuard g;
+      p1.swap(p2);
+    }
+    assert(p1 == TC.value1);
+    assert(p2 == TC.value2);
+  }
+  // self-swap
+  {
+    const char* Val = "aoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeu";
+    path p1(Val);
+    assert(p1 == Val);
+    {
+      DisableAllocationGuard g;
+      p1.swap(p1);
+    }
+    assert(p1 == Val);
+  }
+}

+ 43 - 0
test/std/experimental/filesystem/class.path/path.member/path.native.obs/c_str.pass.cpp

@@ -0,0 +1,43 @@
+
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// const value_type* c_str() const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main()
+{
+  using namespace fs;
+  const char* const value = "hello world";
+  const std::string str_value = value;
+  path p(value);
+  { // Check signature
+    ASSERT_SAME_TYPE(path::value_type const*, decltype(p.c_str()));
+    ASSERT_NOEXCEPT(p.c_str());
+  }
+  {
+    path p(value);
+    assert(p.c_str() == str_value);
+    assert(p.native().c_str() == p.c_str());
+  }
+}

+ 63 - 0
test/std/experimental/filesystem/class.path/path.member/path.native.obs/named_overloads.pass.cpp

@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// std::string  string() const;
+// std::wstring wstring() const;
+// std::u8string  u8string() const;
+// std::u16string u16string() const;
+// std::u32string u32string() const;
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+int main()
+{
+  using namespace fs;
+  auto const& MS = longString;
+  const char* value = longString;
+  const path p(value);
+  {
+    std::string s = p.string();
+    assert(s == value);
+  }
+  {
+    std::string s = p.u8string();
+    assert(s == (const char*)MS);
+  }
+  {
+    std::wstring s = p.wstring();
+    assert(s == (const wchar_t*)MS);
+  }
+  {
+    std::u16string s = p.u16string();
+    assert(s == (const char16_t*)MS);
+  }
+  {
+    std::u32string s = p.u32string();
+    assert(s == (const char32_t*)MS);
+  }
+}

+ 40 - 0
test/std/experimental/filesystem/class.path/path.member/path.native.obs/native.pass.cpp

@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// const string_type& native() const noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main()
+{
+  using namespace fs;
+  const char* const value = "hello world";
+  path p(value);
+  { // Check signature
+    ASSERT_SAME_TYPE(path::string_type const&, decltype(p.native()));
+    ASSERT_NOEXCEPT(p.native());
+  }
+  { // native() is tested elsewhere
+    path p(value);
+    assert(p.native() == value);
+  }
+}

+ 47 - 0
test/std/experimental/filesystem/class.path/path.member/path.native.obs/operator_string.pass.cpp

@@ -0,0 +1,47 @@
+
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// operator string_type() const;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main()
+{
+  using namespace fs;
+  using string_type = path::string_type;
+  const char* const value = "hello world";
+  path p(value);
+  { // Check signature
+    static_assert(std::is_convertible<path, string_type>::value, "");
+    static_assert(std::is_constructible<string_type, path>::value, "");
+    ASSERT_SAME_TYPE(string_type, decltype(p.operator string_type()));
+    ASSERT_NOT_NOEXCEPT(p.operator string_type());
+  }
+  {
+    path p(value);
+    assert(p.native() == value);
+    string_type s = p;
+    assert(s == value);
+    assert(p == value);
+  }
+}

+ 113 - 0
test/std/experimental/filesystem/class.path/path.member/path.native.obs/string_alloc.pass.cpp

@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class ECharT, class Traits = char_traits<ECharT>,
+//           class Allocator = allocator<ECharT>>
+// basic_string<ECharT, Traits, Allocator>
+// string(const Allocator& a = Allocator()) const;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+MultiStringType shortString = MKSTR("abc");
+MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+template <class CharT>
+void doShortStringTest(MultiStringType const& MS) {
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  using Alloc = std::allocator<CharT>;
+  Ptr value = MS;
+  const path p((const char*)MS);
+  {
+      DisableAllocationGuard g; // should not allocate
+      Str s = p.string<CharT>();
+      assert(s == value);
+      Str s2 = p.string<CharT>(Alloc{});
+      assert(s2 == value);
+  }
+}
+
+template <class CharT>
+void doLongStringTest(MultiStringType const& MS) {
+  using namespace fs;
+  using Ptr = CharT const*;
+  using Str = std::basic_string<CharT>;
+  Ptr value = MS;
+  const path p((const char*)MS);
+  { // Default allocator
+      using Alloc = std::allocator<CharT>;
+      RequireAllocationGuard g; // should not allocate because
+      Str s = p.string<CharT>();
+      assert(s == value);
+      Str s2 = p.string<CharT>(Alloc{});
+      assert(s2 == value);
+  }
+  using MAlloc = malloc_allocator<CharT>;
+  MAlloc::reset();
+  { // Other allocator - default construct
+      using Traits = std::char_traits<CharT>;
+      using AStr = std::basic_string<CharT, Traits, MAlloc>;
+      DisableAllocationGuard g;
+      AStr s = p.string<CharT, Traits, MAlloc>();
+      assert(s == value);
+      assert(MAlloc::alloc_count > 0);
+      assert(MAlloc::outstanding_alloc() == 1);
+  }
+  MAlloc::reset();
+  { // Other allocator - provided copy
+      using Traits = std::char_traits<CharT>;
+      using AStr = std::basic_string<CharT, Traits, MAlloc>;
+      DisableAllocationGuard g;
+      MAlloc a;
+      // don't allow another allocator to be default constructed.
+      MAlloc::disable_default_constructor = true;
+      AStr s = p.string<CharT, Traits, MAlloc>(a);
+      assert(s == value);
+      assert(MAlloc::alloc_count > 0);
+      assert(MAlloc::outstanding_alloc() == 1);
+  }
+  MAlloc::reset();
+  /////////////////////////////////////////////////////////////////////////////
+}
+
+int main()
+{
+  using namespace fs;
+  {
+    auto const& S = shortString;
+    doShortStringTest<char>(S);
+    doShortStringTest<wchar_t>(S);
+    doShortStringTest<char16_t>(S);
+    doShortStringTest<char32_t>(S);
+  }
+  {
+    auto const& S = longString;
+    doLongStringTest<char>(S);
+    doLongStringTest<wchar_t>(S);
+    doLongStringTest<char16_t>(S);
+    doLongStringTest<char32_t>(S);
+  }
+}

+ 32 - 0
test/std/experimental/filesystem/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp

@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+//-------------------------------
+// 8.4.10 path query [path.query]
+//-------------------------------
+// bool empty() const noexcept;
+// bool has_root_path() const;
+// bool has_root_name() const;
+// bool has_root_directory() const;
+// bool has_relative_path() const;
+// bool has_parent_path() const;
+// bool has_filename() const;
+// bool has_stem() const;
+// bool has_extension() const;
+// bool is_absolute() const;
+// bool is_relative() const;
+
+// tested in path.decompose
+int main() {}

+ 33 - 0
test/std/experimental/filesystem/class.path/path.nonmember/append_op.pass.cpp

@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// path operator/(path const&, path const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+// This is mainly tested via the member append functions.
+int main()
+{
+  using namespace fs;
+  path p1("abc");
+  path p2("def");
+  path p3 = p1 / p2;
+  assert(p3 == "abc/def");
+}

+ 14 - 0
test/std/experimental/filesystem/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp

@@ -0,0 +1,14 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// The comparison operators are tested as part of [path.compare]
+// in class.path/path.members/path.compare.pass.cpp
+int main() {}

+ 14 - 0
test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp

@@ -0,0 +1,14 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// The "hash_value" function is tested as part of [path.compare]
+// in class.path/path.members/path.compare.pass.cpp
+int main() {}

+ 53 - 0
test/std/experimental/filesystem/class.path/path.nonmember/path.factory.pass.cpp

@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// template <class Source>
+//    path u8path(Source const&);
+// template <class InputIter>
+//   path u8path(InputIter, InputIter);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+int main()
+{
+  using namespace fs;
+  const char* In1 = "abcd/efg";
+  const std::string In2(In1);
+  const auto In3 = In2.begin();
+  const auto In3End = In2.end();
+  {
+    path p = fs::u8path(In1);
+    assert(p == In1);
+  }
+  {
+    path p = fs::u8path(In2);
+    assert(p == In1);
+  }
+  {
+    path p = fs::u8path(In3);
+    assert(p == In1);
+  }
+  {
+    path p = fs::u8path(In3, In3End);
+    assert(p == In1);
+  }
+}

+ 66 - 0
test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp

@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const path& p);
+//
+// template <class charT, class traits>
+// basic_istream<charT, traits>&
+// operator>>(basic_istream<charT, traits>& is, path& p)
+//
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <sstream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType InStr =  MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
+MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
+
+template <class CharT>
+void doIOTest() {
+  using namespace fs;
+  using Ptr = const CharT*;
+  using StrStream = std::basic_stringstream<CharT>;
+  const char* const InCStr = InStr;
+  const Ptr E = OutStr;
+  const path p((const char*)InStr);
+  StrStream ss;
+  { // test output
+    auto& ret = (ss << p);
+    assert(ss.str() == E);
+    assert(&ret == &ss);
+  }
+  { // test input
+    path p_in;
+    auto& ret = ss >> p_in;
+    assert(p_in.native() == (const char*)InStr);
+    assert(&ret == &ss);
+  }
+}
+
+
+int main() {
+  doIOTest<char>();
+  doIOTest<wchar_t>();
+  //doIOTest<char16_t>();
+  //doIOTest<char32_t>();
+}

+ 69 - 0
test/std/experimental/filesystem/class.path/path.nonmember/path.io.unicode_bug.pass.cpp

@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// template <class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const path& p);
+//
+// template <class charT, class traits>
+// basic_istream<charT, traits>&
+// operator>>(basic_istream<charT, traits>& is, path& p)
+//
+
+// TODO(EricWF) This test fails because "std::quoted" fails to compile
+// for char16_t and char32_t types. Combine with path.io.pass.cpp when this
+// passes.
+// XFAIL: *
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <sstream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+MultiStringType InStr =  MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789");
+MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\"");
+
+template <class CharT>
+void doIOTest() {
+  using namespace fs;
+  using Ptr = const CharT*;
+  using StrStream = std::basic_stringstream<CharT>;
+  const char* const InCStr = InStr;
+  const Ptr E = OutStr;
+  const path p((const char*)InStr);
+  StrStream ss;
+  { // test output
+    auto& ret = (ss << p);
+    assert(ss.str() == E);
+    assert(&ret == &ss);
+  }
+  { // test input
+    path p_in;
+    auto& ret = ss >> p_in;
+    assert(p_in.native() == (const char*)InStr);
+    assert(&ret == &ss);
+  }
+}
+
+
+int main() {
+  doIOTest<char16_t>();
+  doIOTest<char32_t>();
+}

+ 50 - 0
test/std/experimental/filesystem/class.path/path.nonmember/swap.pass.cpp

@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// void swap(path& lhs, path& rhs) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "filesystem_test_helper.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+// NOTE: this is tested in path.members/path.modifiers via the member swap.
+int main()
+{
+  using namespace fs;
+  const char* value1 = "foo/bar/baz";
+  const char* value2 = "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG";
+  path p1(value1);
+  path p2(value2);
+  {
+    using namespace std; using namespace fs;
+    ASSERT_NOEXCEPT(swap(p1, p2));
+    ASSERT_SAME_TYPE(void, decltype(swap(p1, p2)));
+  }
+  {
+    DisableAllocationGuard g;
+    using namespace std;
+    using namespace fs;
+    swap(p1, p2);
+    assert(p1.native() == value2);
+    assert(p2.native() == value1);
+    swap(p1, p2);
+    assert(p1.native() == value1);
+    assert(p2.native() == value2);
+  }
+}

+ 39 - 0
test/std/experimental/filesystem/class.path/synop.pass.cpp

@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class path
+
+// typedef ... value_type;
+// typedef basic_string<value_type> string_type;
+// static constexpr value_type preferred_separator = ...;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+int main() {
+  using namespace fs;
+  ASSERT_SAME_TYPE(path::value_type, char);
+  ASSERT_SAME_TYPE(path::string_type, std::basic_string<path::value_type>);
+  {
+    ASSERT_SAME_TYPE(const path::value_type, decltype(path::preferred_separator));
+    static_assert(path::preferred_separator == '/', "");
+    // Make preferred_separator ODR used by taking it's address.
+    const char* dummy = &path::preferred_separator;
+    ((void)dummy);
+  }
+}

+ 79 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/copy.pass.cpp

@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_recursive_directory_iterator(recursive_recursive_directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_copy_construct_tests)
+
+TEST_CASE(test_constructor_signature)
+{
+    using D = recursive_directory_iterator;
+    static_assert(std::is_copy_constructible<D>::value, "");
+    //static_assert(!std::is_nothrow_copy_constructible<D>::value, "");
+}
+
+TEST_CASE(test_copy_end_iterator)
+{
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(endIt);
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_copy_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt{};
+
+    // build 'it' up with "interesting" non-default state so we can test
+    // that it gets copied. We want to get 'it' into a state such that:
+    //  it.options() != directory_options::none
+    //  it.depth() != 0
+    //  it.recursion_pending() != true
+    const directory_options opts = directory_options::skip_permission_denied;
+    recursive_directory_iterator it(testDir, opts);
+    TEST_REQUIRE(it != endIt);
+    while (it.depth() == 0) {
+        ++it;
+        TEST_REQUIRE(it != endIt);
+    }
+    it.disable_recursion_pending();
+    TEST_CHECK(it.options() == opts);
+    TEST_CHECK(it.depth() == 1);
+    TEST_CHECK(it.recursion_pending() == false);
+    const path entry = *it;
+
+    // OPERATION UNDER TEST //
+    const recursive_directory_iterator it2(it);
+    // ------------------- //
+
+    TEST_REQUIRE(it2 == it);
+    TEST_CHECK(*it2 == entry);
+    TEST_CHECK(it2.depth() == 1);
+    TEST_CHECK(it2.recursion_pending() == false);
+    TEST_CHECK(it != endIt);
+}
+
+TEST_SUITE_END()

+ 158 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/copy_assign.pass.cpp

@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_copy_assign_tests)
+
+recursive_directory_iterator createInterestingIterator()
+    // Create an "interesting" iterator where all fields are
+    // in a non-default state. The returned 'it' is in a
+    // state such that:
+    //   it.options() == directory_options::skip_permission_denied
+    //   it.depth() == 1
+    //   it.recursion_pending() == true
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(testDir,
+                                    directory_options::skip_permission_denied);
+    TEST_ASSERT(it != endIt);
+    while (it.depth() != 1) {
+        ++it;
+        TEST_ASSERT(it != endIt);
+    }
+    TEST_ASSERT(it.depth() == 1);
+    it.disable_recursion_pending();
+    return it;
+}
+
+
+recursive_directory_iterator createDifferentInterestingIterator()
+    // Create an "interesting" iterator where all fields are
+    // in a non-default state. The returned 'it' is in a
+    // state such that:
+    //   it.options() == directory_options::follow_directory_symlink
+    //   it.depth() == 2
+    //   it.recursion_pending() == false
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(testDir,
+                                    directory_options::follow_directory_symlink);
+    TEST_ASSERT(it != endIt);
+    while (it.depth() != 2) {
+        ++it;
+        TEST_ASSERT(it != endIt);
+    }
+    TEST_ASSERT(it.depth() == 2);
+    return it;
+}
+
+TEST_CASE(test_assignment_signature) {
+    using D = recursive_directory_iterator;
+    static_assert(std::is_copy_assignable<D>::value, "");
+}
+
+TEST_CASE(test_copy_to_end_iterator)
+{
+    const recursive_directory_iterator endIt;
+
+    const recursive_directory_iterator from = createInterestingIterator();
+    const path entry = *from;
+
+    recursive_directory_iterator to;
+    to = from;
+    TEST_REQUIRE(to == from);
+    TEST_CHECK(*to == entry);
+    TEST_CHECK(to.options() == from.options());
+    TEST_CHECK(to.depth() == from.depth());
+    TEST_CHECK(to.recursion_pending() == from.recursion_pending());
+}
+
+
+TEST_CASE(test_copy_from_end_iterator)
+{
+    const recursive_directory_iterator from;
+    recursive_directory_iterator to = createInterestingIterator();
+
+    to = from;
+    TEST_REQUIRE(to == from);
+    TEST_CHECK(to == recursive_directory_iterator{});
+}
+
+TEST_CASE(test_copy_valid_iterator)
+{
+    const recursive_directory_iterator endIt;
+
+    const recursive_directory_iterator it = createInterestingIterator();
+    const path entry = *it;
+
+    recursive_directory_iterator it2 = createDifferentInterestingIterator();
+    TEST_REQUIRE(it2                   != it);
+    TEST_CHECK(it2.options()           != it.options());
+    TEST_CHECK(it2.depth()             != it.depth());
+    TEST_CHECK(it2.recursion_pending() != it.recursion_pending());
+    TEST_CHECK(*it2                    != entry);
+
+    it2 = it;
+    TEST_REQUIRE(it2                   == it);
+    TEST_CHECK(it2.options()           == it.options());
+    TEST_CHECK(it2.depth()             == it.depth());
+    TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
+    TEST_CHECK(*it2                    == entry);
+}
+
+TEST_CASE(test_returns_reference_to_self)
+{
+    const recursive_directory_iterator it;
+    recursive_directory_iterator it2;
+    recursive_directory_iterator& ref = (it2 = it);
+    TEST_CHECK(&ref == &it2);
+}
+
+TEST_CASE(test_self_copy)
+{
+    // Create two non-equal iterators that have exactly the same state.
+    recursive_directory_iterator it = createInterestingIterator();
+    recursive_directory_iterator it2 = createInterestingIterator();
+    TEST_CHECK(it != it2);
+    TEST_CHECK(it2.options()           == it.options());
+    TEST_CHECK(it2.depth()             == it.depth());
+    TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
+    TEST_CHECK(*it2 == *it);
+
+    // perform a self-copy and check that the state still matches the
+    // other unmodified iterator.
+    recursive_directory_iterator const& cit = it;
+    it = cit;
+    TEST_CHECK(it2.options()           == it.options());
+    TEST_CHECK(it2.depth()             == it.depth());
+    TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
+    TEST_CHECK(*it2 == *it);
+}
+
+TEST_SUITE_END()

+ 240 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp

@@ -0,0 +1,240 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class directory_iterator
+
+//
+// explicit recursive_directory_iterator(const path& p);
+// recursive_directory_iterator(const path& p, directory_options options);
+// recursive_directory_iterator(const path& p, error_code& ec) noexcept;
+// recursive_directory_iterator(const path& p, directory_options options, error_code& ec) noexcept;
+
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+using RDI = recursive_directory_iterator;
+
+TEST_SUITE(recursive_directory_iterator_constructor_tests)
+
+TEST_CASE(test_constructor_signatures)
+{
+    using D = recursive_directory_iterator;
+
+    // explicit directory_iterator(path const&);
+    static_assert(!std::is_convertible<path, D>::value, "");
+    static_assert(std::is_constructible<D, path>::value, "");
+    static_assert(!std::is_nothrow_constructible<D, path>::value, "");
+
+    // directory_iterator(path const&, error_code&) noexcept
+    static_assert(std::is_nothrow_constructible<D, path, std::error_code&>::value, "");
+
+    // directory_iterator(path const&, directory_options);
+    static_assert(std::is_constructible<D, path, directory_options>::value, "");
+    static_assert(!std::is_nothrow_constructible<D, path, directory_options>::value, "");
+
+    // directory_iterator(path const&, directory_options, error_code&) noexcept
+    static_assert(std::is_nothrow_constructible<D, path, directory_options, std::error_code&>::value, "");
+}
+
+TEST_CASE(test_construction_from_bad_path)
+{
+    std::error_code ec;
+    directory_options opts = directory_options::none;
+    const RDI endIt;
+
+    const path testPaths[] = { StaticEnv::DNE, StaticEnv::BadSymlink };
+    for (path const& testPath : testPaths)
+    {
+        {
+            RDI it(testPath, ec);
+            TEST_CHECK(ec);
+            TEST_CHECK(it == endIt);
+        }
+        {
+            RDI it(testPath, opts, ec);
+            TEST_CHECK(ec);
+            TEST_CHECK(it == endIt);
+        }
+        {
+            TEST_CHECK_THROW(filesystem_error, RDI(testPath));
+            TEST_CHECK_THROW(filesystem_error, RDI(testPath, opts));
+        }
+    }
+}
+
+TEST_CASE(access_denied_test_case)
+{
+    using namespace std::experimental::filesystem;
+    scoped_test_env env;
+    path const testDir = env.make_env_path("dir1");
+    path const testFile = testDir / "testFile";
+    env.create_dir(testDir);
+    env.create_file(testFile, 42);
+
+    // Test that we can iterator over the directory before changing the perms
+    RDI it(testDir);
+    TEST_REQUIRE(it != RDI{});
+
+    // Change the permissions so we can no longer iterate
+    permissions(testDir, perms::none);
+
+    // Check that the construction fails when skip_permissions_denied is
+    // not given.
+    {
+        std::error_code ec;
+        RDI it(testDir, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == RDI{});
+    }
+    // Check that construction does not report an error when
+    // 'skip_permissions_denied' is given.
+    {
+        std::error_code ec;
+        RDI it(testDir, directory_options::skip_permission_denied, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it == RDI{});
+    }
+}
+
+
+TEST_CASE(access_denied_to_file_test_case)
+{
+    using namespace std::experimental::filesystem;
+    scoped_test_env env;
+    path const testFile = env.make_env_path("file1");
+    env.create_file(testFile, 42);
+
+    // Change the permissions so we can no longer iterate
+    permissions(testFile, perms::none);
+
+    // Check that the construction fails when skip_permissions_denied is
+    // not given.
+    {
+        std::error_code ec;
+        RDI it(testFile, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == RDI{});
+    }
+    // Check that construction still fails when 'skip_permissions_denied' is given
+    // because we tried to open a file and not a directory.
+    {
+        std::error_code ec;
+        RDI it(testFile, directory_options::skip_permission_denied, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == RDI{});
+    }
+}
+
+TEST_CASE(test_open_on_empty_directory_equals_end)
+{
+    scoped_test_env env;
+    const path testDir = env.make_env_path("dir1");
+    env.create_dir(testDir);
+
+    const RDI endIt;
+    {
+        std::error_code ec;
+        RDI it(testDir, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(it == endIt);
+    }
+    {
+        RDI it(testDir);
+        TEST_CHECK(it == endIt);
+    }
+}
+
+TEST_CASE(test_open_on_directory_succeeds)
+{
+    const path testDir = StaticEnv::Dir;
+    std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
+                                std::end(  StaticEnv::DirIterationList));
+    const RDI endIt{};
+
+    {
+        std::error_code ec;
+        RDI it(testDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it != endIt);
+        TEST_CHECK(dir_contents.count(*it));
+    }
+    {
+        RDI it(testDir);
+        TEST_CHECK(it != endIt);
+        TEST_CHECK(dir_contents.count(*it));
+    }
+}
+
+TEST_CASE(test_open_on_file_fails)
+{
+    const path testFile = StaticEnv::File;
+    const RDI endIt{};
+    {
+        std::error_code ec;
+        RDI it(testFile, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(it == endIt);
+    }
+    {
+        TEST_CHECK_THROW(filesystem_error, RDI(testFile));
+    }
+}
+
+TEST_CASE(test_options_post_conditions)
+{
+    const path goodDir = StaticEnv::Dir;
+    const path badDir = StaticEnv::DNE;
+
+    {
+        std::error_code ec;
+
+        RDI it1(goodDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it1.options() == directory_options::none);
+
+        RDI it2(badDir, ec);
+        TEST_REQUIRE(ec);
+        TEST_REQUIRE(it2 == RDI{});
+    }
+    {
+        std::error_code ec;
+        const directory_options opts = directory_options::skip_permission_denied;
+
+        RDI it1(goodDir, opts, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(it1.options() == opts);
+
+        RDI it2(badDir, opts, ec);
+        TEST_REQUIRE(ec);
+        TEST_REQUIRE(it2 == RDI{});
+    }
+    {
+        RDI it(goodDir);
+        TEST_CHECK(it.options() == directory_options::none);
+    }
+    {
+        const directory_options opts = directory_options::follow_directory_symlink;
+        RDI it(goodDir, opts);
+        TEST_CHECK(it.options() == opts);
+    }
+}
+TEST_SUITE_END()

+ 66 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/depth.pass.cpp

@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// int depth() const
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_depth_tests)
+
+TEST_CASE(test_depth)
+{
+    const path testDir = StaticEnv::Dir;
+    const path DirDepth1 = StaticEnv::Dir2;
+    const path DirDepth2 = StaticEnv::Dir3;
+    const recursive_directory_iterator endIt{};
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+    TEST_CHECK(it.depth() == 0);
+
+    bool seen_d1, seen_d2;
+    seen_d1 = seen_d2 = false;
+
+    while (it != endIt) {
+        const path entry = *it;
+        const path parent = entry.parent_path();
+        if (parent == testDir) {
+            TEST_CHECK(it.depth() == 0);
+        } else if (parent == DirDepth1) {
+            TEST_CHECK(it.depth() == 1);
+            seen_d1 = true;
+        } else if (parent == DirDepth2) {
+            TEST_CHECK(it.depth() == 2);
+            seen_d2 = true;
+        } else {
+            TEST_CHECK(!"Unexpected depth while iterating over static env");
+        }
+        ++it;
+    }
+    TEST_REQUIRE(seen_d1 && seen_d2);
+    TEST_CHECK(it == endIt);
+}
+
+TEST_SUITE_END()

+ 43 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/disable_recursion_pending.pass.cpp

@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// void disable_recursion_pending();
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_disable_recursion_pending_tests)
+
+// NOTE: The main semantics of disable_recursion_pending are tested
+// in the 'recursion_pending()' tests.
+TEST_CASE(basic_test)
+{
+    recursive_directory_iterator it(StaticEnv::Dir);
+    TEST_REQUIRE(it.recursion_pending() == true);
+    it.disable_recursion_pending();
+    TEST_CHECK(it.recursion_pending() == false);
+    it.disable_recursion_pending();
+    TEST_CHECK(it.recursion_pending() == false);
+}
+
+TEST_SUITE_END()

+ 228 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/increment.pass.cpp

@@ -0,0 +1,228 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_directory_iterator& operator++();
+// recursive_directory_iterator& increment(error_code& ec) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_increment_tests)
+
+TEST_CASE(test_increment_signatures)
+{
+    using D = recursive_directory_iterator;
+    recursive_directory_iterator d; ((void)d);
+    std::error_code ec; ((void)ec);
+
+    ASSERT_SAME_TYPE(decltype(++d), recursive_directory_iterator&);
+    ASSERT_NOT_NOEXCEPT(++d);
+
+    ASSERT_SAME_TYPE(decltype(d.increment(ec)), recursive_directory_iterator&);
+    ASSERT_NOEXCEPT(d.increment(ec));
+}
+
+TEST_CASE(test_prefix_increment)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
+                                      std::end(  StaticEnv::RecDirIterationList));
+    const recursive_directory_iterator endIt{};
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        recursive_directory_iterator& it_ref = ++it;
+        TEST_CHECK(&it_ref == &it);
+    }
+
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_postfix_increment)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
+                                      std::end(  StaticEnv::RecDirIterationList));
+    const recursive_directory_iterator endIt{};
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        const path entry2 = *it++;
+        TEST_CHECK(entry2 == entry);
+    }
+    TEST_CHECK(it == endIt);
+}
+
+
+TEST_CASE(test_increment_method)
+{
+    const path testDir = StaticEnv::Dir;
+    const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
+                                      std::end(  StaticEnv::RecDirIterationList));
+    const recursive_directory_iterator endIt{};
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        recursive_directory_iterator& it_ref = it.increment(ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(&it_ref == &it);
+    }
+
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(test_follow_symlinks)
+{
+    const path testDir = StaticEnv::Dir;
+    auto const& IterList = StaticEnv::RecDirFollowSymlinksIterationList;
+
+    const std::set<path> dir_contents(std::begin(IterList), std::end(IterList));
+    const recursive_directory_iterator endIt{};
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir,
+                              directory_options::follow_directory_symlink, ec);
+    TEST_REQUIRE(!ec);
+
+    std::set<path> unseen_entries = dir_contents;
+    while (!unseen_entries.empty()) {
+        TEST_REQUIRE(it != endIt);
+        const path entry = *it;
+
+        TEST_REQUIRE(unseen_entries.erase(entry) == 1);
+        recursive_directory_iterator& it_ref = it.increment(ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(&it_ref == &it);
+    }
+    TEST_CHECK(it == endIt);
+}
+
+TEST_CASE(access_denied_on_recursion_test_case)
+{
+    using namespace std::experimental::filesystem;
+    scoped_test_env env;
+    const path testFiles[] = {
+        env.create_dir("dir1"),
+        env.create_dir("dir1/dir2"),
+        env.create_file("dir1/dir2/file1"),
+        env.create_file("dir1/file2")
+    };
+    const path startDir = testFiles[0];
+    const path permDeniedDir = testFiles[1];
+    const path otherFile = testFiles[3];
+
+    // Change the permissions so we can no longer iterate
+    permissions(permDeniedDir, perms::none);
+
+    const recursive_directory_iterator endIt;
+
+    // Test that recursion resulting in a "EACCESS" error is not ignored
+    // by default.
+    {
+        std::error_code ec;
+        recursive_directory_iterator it(startDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_REQUIRE(it != endIt);
+        const path elem = *it;
+        TEST_REQUIRE(elem == permDeniedDir);
+
+        it.increment(ec);
+        TEST_REQUIRE(ec);
+        TEST_REQUIRE(it == endIt);
+    }
+    // Same as obove but test operator++().
+    {
+        std::error_code ec;
+        recursive_directory_iterator it(startDir, ec);
+        TEST_REQUIRE(!ec);
+        TEST_REQUIRE(it != endIt);
+        const path elem = *it;
+        TEST_REQUIRE(elem == permDeniedDir);
+
+        TEST_REQUIRE_THROW(filesystem_error, ++it);
+    }
+    // Test that recursion resulting in a "EACCESS" error is ignored when the
+    // correct options are given to the constructor.
+    {
+        std::error_code ec;
+        recursive_directory_iterator it(
+            startDir,directory_options::skip_permission_denied,
+                                        ec);
+        TEST_REQUIRE(!ec);
+        TEST_REQUIRE(it != endIt);
+        const path elem = *it;
+        TEST_REQUIRE(elem == permDeniedDir);
+
+        it.increment(ec);
+        TEST_REQUIRE(!ec);
+        TEST_REQUIRE(it != endIt);
+        TEST_CHECK(*it == otherFile);
+    }
+    // Test that construction resulting in a "EACCESS" error is not ignored
+    // by default.
+    {
+        std::error_code ec;
+        recursive_directory_iterator it(permDeniedDir, ec);
+        TEST_REQUIRE(ec);
+        TEST_REQUIRE(it == endIt);
+    }
+    // Same as obove but testing the throwing constructors
+    {
+        TEST_REQUIRE_THROW(filesystem_error,
+                           recursive_directory_iterator(permDeniedDir));
+    }
+    // Test that construction resulting in a "EACCESS" error constructs the
+    // end iterator when the correct options are given.
+    {
+        std::error_code ec;
+        recursive_directory_iterator it(permDeniedDir,
+                                        directory_options::skip_permission_denied,
+                                        ec);
+        TEST_REQUIRE(!ec);
+        TEST_REQUIRE(it == endIt);
+    }
+}
+
+TEST_SUITE_END()

+ 80 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/move.pass.cpp

@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_directory_iterator(recursive_directory_iterator&&) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_move_construct_tests)
+
+TEST_CASE(test_constructor_signature)
+{
+    using D = recursive_directory_iterator;
+    static_assert(std::is_nothrow_move_constructible<D>::value, "");
+}
+
+TEST_CASE(test_move_end_iterator)
+{
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator endIt2{};
+
+    recursive_directory_iterator it(std::move(endIt2));
+    TEST_CHECK(it == endIt);
+    TEST_CHECK(endIt2 == endIt);
+}
+
+TEST_CASE(test_move_valid_iterator)
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt{};
+
+    // build 'it' up with "interesting" non-default state so we can test
+    // that it gets copied. We want to get 'it' into a state such that:
+    //  it.options() != directory_options::none
+    //  it.depth() != 0
+    //  it.recursion_pending() != true
+    const directory_options opts = directory_options::skip_permission_denied;
+    recursive_directory_iterator it(testDir, opts);
+    TEST_REQUIRE(it != endIt);
+    while (it.depth() == 0) {
+        ++it;
+        TEST_REQUIRE(it != endIt);
+    }
+    it.disable_recursion_pending();
+    TEST_CHECK(it.options() == opts);
+    TEST_CHECK(it.depth() == 1);
+    TEST_CHECK(it.recursion_pending() == false);
+    const path entry = *it;
+
+    // OPERATION UNDER TEST //
+    const recursive_directory_iterator it2(std::move(it));
+    // ------------------- //
+
+    TEST_REQUIRE(it2 != endIt);
+    TEST_CHECK(*it2 == entry);
+    TEST_CHECK(it2.depth() == 1);
+    TEST_CHECK(it2.recursion_pending() == false);
+}
+
+TEST_SUITE_END()

+ 163 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/move_assign.pass.cpp

@@ -0,0 +1,163 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_directory_iterator& operator=(recursive_directory_iterator const&);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_move_assign_tests)
+
+recursive_directory_iterator createInterestingIterator()
+    // Create an "interesting" iterator where all fields are
+    // in a non-default state. The returned 'it' is in a
+    // state such that:
+    //   it.options() == directory_options::skip_permission_denied
+    //   it.depth() == 1
+    //   it.recursion_pending() == true
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(testDir,
+                                    directory_options::skip_permission_denied);
+    TEST_ASSERT(it != endIt);
+    while (it.depth() != 1) {
+        ++it;
+        TEST_ASSERT(it != endIt);
+    }
+    TEST_ASSERT(it.depth() == 1);
+    it.disable_recursion_pending();
+    return it;
+}
+
+recursive_directory_iterator createDifferentInterestingIterator()
+    // Create an "interesting" iterator where all fields are
+    // in a non-default state. The returned 'it' is in a
+    // state such that:
+    //   it.options() == directory_options::follow_directory_symlink
+    //   it.depth() == 2
+    //   it.recursion_pending() == false
+{
+    const path testDir = StaticEnv::Dir;
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(testDir,
+                                    directory_options::follow_directory_symlink);
+    TEST_ASSERT(it != endIt);
+    while (it.depth() != 2) {
+        ++it;
+        TEST_ASSERT(it != endIt);
+    }
+    TEST_ASSERT(it.depth() == 2);
+    return it;
+}
+
+
+TEST_CASE(test_assignment_signature)
+{
+    using D = recursive_directory_iterator;
+    static_assert(std::is_nothrow_move_assignable<D>::value, "");
+}
+
+
+TEST_CASE(test_move_to_end_iterator)
+{
+    const recursive_directory_iterator endIt;
+
+    recursive_directory_iterator from = createInterestingIterator();
+    const recursive_directory_iterator from_copy(from);
+    const path entry = *from;
+
+    recursive_directory_iterator to;
+    to = std::move(from);
+    TEST_REQUIRE(to != endIt);
+    TEST_CHECK(*to == entry);
+    TEST_CHECK(to.options() == from_copy.options());
+    TEST_CHECK(to.depth() == from_copy.depth());
+    TEST_CHECK(to.recursion_pending() == from_copy.recursion_pending());
+    TEST_CHECK(from == endIt || from == to);
+}
+
+
+TEST_CASE(test_move_from_end_iterator)
+{
+    recursive_directory_iterator from;
+    recursive_directory_iterator to = createInterestingIterator();
+
+    to = std::move(from);
+    TEST_REQUIRE(to == from);
+    TEST_CHECK(to == recursive_directory_iterator{});
+}
+
+TEST_CASE(test_move_valid_iterator)
+{
+    const recursive_directory_iterator endIt;
+
+    recursive_directory_iterator it = createInterestingIterator();
+    const recursive_directory_iterator it_copy(it);
+    const path entry = *it;
+
+    recursive_directory_iterator it2 = createDifferentInterestingIterator();
+    const recursive_directory_iterator it2_copy(it2);
+    TEST_REQUIRE(it2 != it);
+    TEST_CHECK(it2.options() != it.options());
+    TEST_CHECK(it2.depth() != it.depth());
+    TEST_CHECK(it2.recursion_pending() != it.recursion_pending());
+    TEST_CHECK(*it2 != entry);
+
+    it2 = std::move(it);
+    TEST_REQUIRE(it2 != it2_copy && it2 != endIt);
+    TEST_CHECK(it2.options() == it_copy.options());
+    TEST_CHECK(it2.depth() == it_copy.depth());
+    TEST_CHECK(it2.recursion_pending() == it_copy.recursion_pending());
+    TEST_CHECK(*it2 == entry);
+    TEST_CHECK(it == endIt || it == it2);
+}
+
+TEST_CASE(test_returns_reference_to_self)
+{
+    recursive_directory_iterator it;
+    recursive_directory_iterator it2;
+    recursive_directory_iterator& ref = (it2 = std::move(it));
+    TEST_CHECK(&ref == &it2);
+}
+
+TEST_CASE(test_self_move)
+{
+    // Create two non-equal iterators that have exactly the same state.
+    recursive_directory_iterator it = createInterestingIterator();
+    recursive_directory_iterator it2 = createInterestingIterator();
+    TEST_CHECK(it != it2);
+    TEST_CHECK(it2.options()           == it.options());
+    TEST_CHECK(it2.depth()             == it.depth());
+    TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
+    TEST_CHECK(*it2 == *it);
+
+    it = std::move(it);
+    TEST_CHECK(it2.options()           == it.options());
+    TEST_CHECK(it2.depth()             == it.depth());
+    TEST_CHECK(it2.recursion_pending() == it.recursion_pending());
+    TEST_CHECK(*it2 == *it);
+}
+
+
+TEST_SUITE_END()

+ 93 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/pop.pass.cpp

@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// void pop();
+// void pop(error_code& ec);
+
+#include <experimental/filesystem>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_pop_tests)
+
+TEST_CASE(signature_tests)
+{
+    recursive_directory_iterator it{}; ((void)it);
+    std::error_code ec; ((void)ec);
+    ASSERT_NOT_NOEXCEPT(it.pop());
+    ASSERT_NOT_NOEXCEPT(it.pop(ec)); // may require allocation or other things
+}
+
+// NOTE: Since the order of iteration is unspecified we use a list of
+// seen files at each depth to determine the new depth after a 'pop()' operation.
+TEST_CASE(test_depth)
+{
+    const recursive_directory_iterator endIt{};
+
+    auto& DE0 = StaticEnv::DirIterationList;
+    std::set<path> notSeenDepth0(std::begin(DE0), std::end(DE0));
+
+    auto& DE1 = StaticEnv::DirIterationListDepth1;
+    std::set<path> notSeenDepth1(std::begin(DE1), std::end(DE1));
+
+    std::error_code ec;
+    recursive_directory_iterator it(StaticEnv::Dir, ec);
+    TEST_REQUIRE(it != endIt);
+    TEST_CHECK(it.depth() == 0);
+
+    while (it.depth() != 2) {
+        if (it.depth() == 0)
+            notSeenDepth0.erase(it->path());
+        else
+            notSeenDepth1.erase(it->path());
+        ++it;
+        TEST_REQUIRE(it != endIt);
+    }
+
+    while (true) {
+        auto set_ec = std::make_error_code(std::errc::address_in_use);
+        it.pop(set_ec);
+        TEST_REQUIRE(!set_ec);
+
+        if (it == endIt) {
+            // We must have seen every entry at depth 0 and 1.
+            TEST_REQUIRE(notSeenDepth0.empty() && notSeenDepth1.empty());
+            break;
+        }
+        else if (it.depth() == 1) {
+            // If we popped to depth 1 then there must be unseen entries
+            // at this level.
+            TEST_REQUIRE(!notSeenDepth1.empty());
+            TEST_CHECK(notSeenDepth1.count(it->path()));
+            notSeenDepth1.clear();
+        }
+        else if (it.depth() == 0) {
+            // If we popped to depth 0 there must be unseen entries at this
+            // level. There should also be no unseen entries at depth 1.
+            TEST_REQUIRE(!notSeenDepth0.empty());
+            TEST_REQUIRE(notSeenDepth1.empty());
+            TEST_CHECK(notSeenDepth0.count(it->path()));
+            notSeenDepth0.clear();
+        }
+    }
+}
+
+TEST_SUITE_END()

+ 145 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.members/recursion_pending.pass.cpp

@@ -0,0 +1,145 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// bool recursion_pending() const;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_recursion_pending_tests)
+
+TEST_CASE(initial_value_test)
+{
+    recursive_directory_iterator it(StaticEnv::Dir);
+    TEST_REQUIRE(it.recursion_pending() == true);
+}
+
+TEST_CASE(value_after_copy_construction_and_assignment_test)
+{
+    recursive_directory_iterator rec_pending_it(StaticEnv::Dir);
+    recursive_directory_iterator no_rec_pending_it(StaticEnv::Dir);
+    no_rec_pending_it.disable_recursion_pending();
+
+    { // copy construction
+        recursive_directory_iterator it(rec_pending_it);
+        TEST_CHECK(it.recursion_pending() == true);
+        it.disable_recursion_pending();
+        TEST_REQUIRE(rec_pending_it.recursion_pending() == true);
+
+        recursive_directory_iterator it2(no_rec_pending_it);
+        TEST_CHECK(it2.recursion_pending() == false);
+    }
+    { // copy assignment
+        recursive_directory_iterator it(StaticEnv::Dir);
+        it.disable_recursion_pending();
+        it = rec_pending_it;
+        TEST_CHECK(it.recursion_pending() == true);
+        it.disable_recursion_pending();
+        TEST_REQUIRE(rec_pending_it.recursion_pending() == true);
+
+        recursive_directory_iterator it2(StaticEnv::Dir);
+        it2 = no_rec_pending_it;
+        TEST_CHECK(it2.recursion_pending() == false);
+    }
+    TEST_CHECK(rec_pending_it.recursion_pending() == true);
+    TEST_CHECK(no_rec_pending_it.recursion_pending() == false);
+}
+
+
+TEST_CASE(value_after_move_construction_and_assignment_test)
+{
+    recursive_directory_iterator rec_pending_it(StaticEnv::Dir);
+    recursive_directory_iterator no_rec_pending_it(StaticEnv::Dir);
+    no_rec_pending_it.disable_recursion_pending();
+
+    { // move construction
+        recursive_directory_iterator it_cp(rec_pending_it);
+        recursive_directory_iterator it(std::move(it_cp));
+        TEST_CHECK(it.recursion_pending() == true);
+
+        recursive_directory_iterator it_cp2(no_rec_pending_it);
+        recursive_directory_iterator it2(std::move(it_cp2));
+        TEST_CHECK(it2.recursion_pending() == false);
+    }
+    { // copy assignment
+        recursive_directory_iterator it(StaticEnv::Dir);
+        it.disable_recursion_pending();
+        recursive_directory_iterator it_cp(rec_pending_it);
+        it = std::move(it_cp);
+        TEST_CHECK(it.recursion_pending() == true);
+
+        recursive_directory_iterator it2(StaticEnv::Dir);
+        recursive_directory_iterator it_cp2(no_rec_pending_it);
+        it2 = std::move(it_cp2);
+        TEST_CHECK(it2.recursion_pending() == false);
+    }
+    TEST_CHECK(rec_pending_it.recursion_pending() == true);
+    TEST_CHECK(no_rec_pending_it.recursion_pending() == false);
+}
+
+TEST_CASE(increment_resets_value)
+{
+    const recursive_directory_iterator endIt;
+    {
+        recursive_directory_iterator it(StaticEnv::Dir);
+        it.disable_recursion_pending();
+        TEST_CHECK(it.recursion_pending() == false);
+        ++it;
+        TEST_CHECK(it.recursion_pending() == true);
+        TEST_CHECK(it.depth() == 0);
+    }
+    {
+        recursive_directory_iterator it(StaticEnv::Dir);
+        it.disable_recursion_pending();
+        TEST_CHECK(it.recursion_pending() == false);
+        it++;
+        TEST_CHECK(it.recursion_pending() == true);
+        TEST_CHECK(it.depth() == 0);
+    }
+    {
+        recursive_directory_iterator it(StaticEnv::Dir);
+        it.disable_recursion_pending();
+        TEST_CHECK(it.recursion_pending() == false);
+        std::error_code ec;
+        it.increment(ec);
+        TEST_CHECK(it.recursion_pending() == true);
+        TEST_CHECK(it.depth() == 0);
+    }
+}
+
+TEST_CASE(pop_does_not_reset_value)
+{
+    const recursive_directory_iterator endIt;
+    recursive_directory_iterator it(StaticEnv::Dir);
+
+    while (it.depth() == 0) {
+        ++it;
+        TEST_REQUIRE(it != endIt);
+    }
+    it.disable_recursion_pending();
+    it.pop();
+    TEST_REQUIRE(it != endIt);
+    TEST_CHECK(it.recursion_pending() == false);
+}
+
+TEST_SUITE_END()

+ 61 - 0
test/std/experimental/filesystem/class.rec.dir.itr/rec.dir.itr.nonmembers/begin_end.pass.cpp

@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// class recursive_directory_iterator
+
+// recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
+// recursive_directory_iterator end(recursive_directory_iterator iter) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <set>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+#include <iostream>
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(recursive_directory_iterator_begin_end_tests)
+
+TEST_CASE(test_function_signatures)
+{
+    using D = recursive_directory_iterator;
+    recursive_directory_iterator d; ((void)d);
+
+    ASSERT_SAME_TYPE(decltype(begin(d)), recursive_directory_iterator);
+    ASSERT_NOEXCEPT(begin(std::move(d)));
+
+    ASSERT_SAME_TYPE(decltype(end(d)), recursive_directory_iterator);
+    ASSERT_NOEXCEPT(end(std::move(d)));
+}
+
+TEST_CASE(test_ranged_for_loop)
+{
+    const path testDir = StaticEnv::Dir;
+    std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList),
+                                std::end(  StaticEnv::RecDirIterationList));
+
+    std::error_code ec;
+    recursive_directory_iterator it(testDir, ec);
+    TEST_REQUIRE(!ec);
+
+    for (auto& elem : it) {
+        TEST_CHECK(dir_contents.erase(elem) == 1);
+    }
+    TEST_CHECK(dir_contents.empty());
+}
+
+TEST_SUITE_END()

+ 75 - 0
test/std/experimental/filesystem/fs.enum/check_bitmask_types.hpp

@@ -0,0 +1,75 @@
+#ifndef TEST_BITMASK_TYPE_HPP
+#define TEST_BITMASK_TYPE_HPP
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+template <class EnumType, EnumType Val1, EnumType Val2,
+          class UT = typename std::underlying_type<EnumType>::type,
+          UT UVal1 = static_cast<UT>(Val1),
+          UT UVal2 = static_cast<UT>(Val2),
+          UT UZero = static_cast<UT>(0),
+          EnumType Zero = static_cast<EnumType>(0)
+        >
+struct check_bitmask_type {
+
+  static constexpr UT dcast(EnumType e) { return static_cast<UT>(e); }
+  static constexpr UT unpromote(decltype(~UZero) promoted) { return static_cast<UT>(promoted); }
+  // We need two values that are non-zero and share at least one bit.
+  static_assert(Val1 != Zero && Val2 != Zero, "");
+  static_assert(Val1 != Val2, "");
+  static_assert((UVal1 & UVal2) == 0, "");
+
+
+  static bool check()
+  {
+    {
+      EnumType ValRef = Val1;
+      ASSERT_SAME_TYPE(EnumType, decltype(Val1 & Val2));
+      ASSERT_SAME_TYPE(EnumType, decltype(Val1 | Val2));
+      ASSERT_SAME_TYPE(EnumType, decltype(Val1 ^ Val2));
+      ASSERT_SAME_TYPE(EnumType, decltype(~Val1));
+      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef &= Val2));
+      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef |= Val2));
+      ASSERT_SAME_TYPE(EnumType&, decltype(ValRef ^= Val2));
+    }
+
+    static_assert((Val1 & Zero) == Zero, "");
+    static_assert((Val1 & Val1) == Val1, "");
+    static_assert(dcast(Val1 & Val2) == (UVal1 & UVal2), "");
+
+    static_assert((Val1 | Zero) == Val1, "");
+    static_assert(dcast(Val1 | Val2) == (UVal1 | UVal2), "");
+
+    static_assert((Val1 ^ Zero) == Val1, "");
+    static_assert(dcast(Val1 ^ Val2) == (UVal1 ^ UVal2), "");
+
+    static_assert(dcast(~Zero) == unpromote(~UZero), "");
+    static_assert(dcast(~Val1) == unpromote(~UVal1), "");
+
+    {
+      EnumType e = Val1;
+      EnumType& eref = (e &= Val2);
+      assert(&eref == &e);
+      assert(dcast(eref) == (UVal1 & UVal2));
+    }
+    {
+      EnumType e = Val1;
+      EnumType& eref = (e |= Val2);
+      assert(&eref == &e);
+      assert(dcast(eref) == (UVal1 | UVal2));
+    }
+    {
+      EnumType e = Val1;
+      EnumType& eref = (e ^= Val2);
+      assert(&eref == &e);
+      assert(dcast(eref) == (UVal1 ^ UVal2));
+    }
+    return true;
+  }
+};
+
+#endif // TEST_BITMASK_TYPE

+ 64 - 0
test/std/experimental/filesystem/fs.enum/enum.copy_options.pass.cpp

@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// enum class copy_options;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "check_bitmask_types.hpp"
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+constexpr fs::copy_options ME(int val) { return static_cast<fs::copy_options>(val); }
+
+int main() {
+  typedef fs::copy_options E;
+  static_assert(std::is_enum<E>::value, "");
+
+  // Check that E is a scoped enum by checking for conversions.
+  typedef std::underlying_type<E>::type UT;
+  static_assert(!std::is_convertible<E, UT>::value, "");
+
+  static_assert(std::is_same<UT, unsigned short>::value, ""); // Implementation detail
+
+  typedef check_bitmask_type<E, E::skip_existing, E::update_existing> BitmaskTester;
+  assert(BitmaskTester::check());
+
+  static_assert(
+          E::none == ME(0),
+        "Expected enumeration values do not match");
+  // Option group for copy_file
+  static_assert(
+          E::skip_existing      == ME(1) &&
+          E::overwrite_existing == ME(2) &&
+          E::update_existing    == ME(4),
+        "Expected enumeration values do not match");
+  // Option group for copy on directories
+  static_assert(
+          E::recursive == ME(8),
+        "Expected enumeration values do not match");
+  // Option group for copy on symlinks
+  static_assert(
+          E::copy_symlinks == ME(16) &&
+          E::skip_symlinks == ME(32),
+        "Expected enumeration values do not match");
+  // Option group for changing form of copy
+  static_assert(
+          E::directories_only    == ME(64) &&
+          E::create_symlinks     == ME(128) &&
+          E::create_hard_links   == ME(256),
+        "Expected enumeration values do not match");
+}

+ 46 - 0
test/std/experimental/filesystem/fs.enum/enum.directory_options.pass.cpp

@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// enum class directory_options;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+#include <sys/stat.h>
+
+#include "test_macros.h"
+#include "check_bitmask_types.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+constexpr fs::directory_options ME(int val) { return static_cast<fs::directory_options>(val); }
+
+int main() {
+  typedef fs::directory_options E;
+  static_assert(std::is_enum<E>::value, "");
+
+  // Check that E is a scoped enum by checking for conversions.
+  typedef std::underlying_type<E>::type UT;
+  static_assert(!std::is_convertible<E, UT>::value, "");
+  static_assert(std::is_same<UT, unsigned char>::value, "");
+
+  typedef check_bitmask_type<E, E::follow_directory_symlink, E::skip_permission_denied> BitmaskTester;
+  assert(BitmaskTester::check());
+
+  static_assert(
+        E::none                     == ME(0) &&
+        E::follow_directory_symlink == ME(1) &&
+        E::skip_permission_denied   == ME(2),
+        "Expected enumeration values do not match");
+
+}

+ 48 - 0
test/std/experimental/filesystem/fs.enum/enum.file_type.pass.cpp

@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// enum class file_type;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace fs = std::experimental::filesystem;
+
+constexpr fs::file_type ME(int val) { return static_cast<fs::file_type>(val); }
+
+int main() {
+  typedef fs::file_type E;
+  static_assert(std::is_enum<E>::value, "");
+
+  // Check that E is a scoped enum by checking for conversions.
+  typedef std::underlying_type<E>::type UT;
+  static_assert(!std::is_convertible<E, UT>::value, "");
+
+  static_assert(std::is_same<UT, signed char>::value, ""); // Implementation detail
+
+  static_assert(
+          E::none == ME(0) &&
+          E::not_found == ME(-1) &&
+          E::regular == ME(1) &&
+          E::directory == ME(2) &&
+          E::symlink == ME(3) &&
+          E::block == ME(4) &&
+          E::character == ME(5) &&
+          E::fifo == ME(6) &&
+          E::socket == ME(7) &&
+          E::unknown == ME(8),
+        "Expected enumeration values do not match");
+}

+ 68 - 0
test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp

@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// enum class perms;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+#include <sys/stat.h>
+
+#include "test_macros.h"
+#include "check_bitmask_types.hpp"
+
+namespace fs = std::experimental::filesystem;
+
+constexpr fs::perms ME(int val) { return static_cast<fs::perms>(val); }
+
+int main() {
+  typedef fs::perms E;
+  static_assert(std::is_enum<E>::value, "");
+
+  // Check that E is a scoped enum by checking for conversions.
+  typedef std::underlying_type<E>::type UT;
+  static_assert(!std::is_convertible<E, UT>::value, "");
+
+  static_assert(std::is_same<UT, unsigned >::value, ""); // Implementation detail
+
+  typedef check_bitmask_type<E, E::group_all, E::owner_all> BitmaskTester;
+  assert(BitmaskTester::check());
+
+  static_assert(
+        E::none         == ME(0) &&
+
+        E::owner_read   == ME(0400) &&
+        E::owner_write  == ME(0200) &&
+        E::owner_exec   == ME(0100) &&
+        E::owner_all    == ME(0700) &&
+
+        E::group_read   == ME(040) &&
+        E::group_write  == ME(020) &&
+        E::group_exec   == ME(010) &&
+        E::group_all    == ME(070) &&
+
+        E::others_read  == ME(04) &&
+        E::others_write == ME(02) &&
+        E::others_exec  == ME(01) &&
+        E::others_all   == ME(07) &&
+        E::all          == ME(0777) &&
+        E::set_uid      == ME(04000) &&
+        E::set_gid      == ME(02000) &&
+        E::sticky_bit   == ME(01000) &&
+        E::mask         == ME(07777) &&
+        E::unknown      == ME(0xFFFF) &&
+        E::add_perms        == ME(0x10000) &&
+        E::remove_perms     == ME(0x20000) &&
+        E::resolve_symlinks == ME(0x40000),
+        "Expected enumeration values do not match");
+}

+ 12 - 0
test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp

@@ -0,0 +1,12 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int main()
+{
+}

+ 31 - 0
test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp

@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// typedef TrivialClock file_time_type;
+
+#include <experimental/filesystem>
+#include <chrono>
+#include <type_traits>
+
+// system_clock is used because it meets the requirements of TrivialClock,
+// and it's resolution and range of system_clock should match the operating
+// systems file time type.
+typedef std::chrono::system_clock              ExpectedClock;
+typedef std::chrono::time_point<ExpectedClock> ExpectedTimePoint;
+
+int main() {
+  static_assert(std::is_same<
+          std::experimental::filesystem::file_time_type,
+          ExpectedTimePoint
+      >::value, "");
+}

+ 117 - 0
test/std/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.cpp

@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// path absolute(const path& p, const path& base=current_path());
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(filesystem_absolute_path_test_suite)
+
+TEST_CASE(absolute_signature_test)
+{
+    const path p; ((void)p);
+    ASSERT_NOT_NOEXCEPT(absolute(p));
+    ASSERT_NOT_NOEXCEPT(absolute(p, p));
+}
+
+// There are 4 cases is the proposal for absolute path.
+// Each scope tests one of the cases.
+TEST_CASE(absolute_path_test)
+{
+    // has_root_name() && has_root_directory()
+    {
+        const path p("//net/foo");
+        const path base("//net/bar/baz");
+        TEST_REQUIRE(p.has_root_name());
+        TEST_REQUIRE(p.has_root_directory());
+        TEST_CHECK(p.is_absolute());
+        path ret = absolute(p, base);
+        TEST_CHECK(ret.is_absolute());
+        TEST_CHECK(ret == p);
+    }
+    // !has_root_name() && has_root_directory()
+    {
+        const path p("/foo");
+        const path base("//net/bar");
+        TEST_REQUIRE(not p.has_root_name());
+        TEST_REQUIRE(p.has_root_directory());
+        TEST_CHECK(p.is_absolute());
+        // ensure absolute(base) is not recursivly called
+        TEST_REQUIRE(base.has_root_name());
+        TEST_REQUIRE(base.has_root_directory());
+
+        path ret = absolute(p, base);
+        TEST_CHECK(ret.is_absolute());
+        TEST_CHECK(ret.has_root_name());
+        TEST_CHECK(ret.root_name() == path("//net"));
+        TEST_CHECK(ret.has_root_directory());
+        TEST_CHECK(ret.root_directory() == path("/"));
+        TEST_CHECK(ret == path("//net/foo"));
+    }
+    // has_root_name() && !has_root_directory()
+    {
+        const path p("//net");
+        const path base("//net/foo/bar");
+        TEST_REQUIRE(p.has_root_name());
+        TEST_REQUIRE(not p.has_root_directory());
+        TEST_CHECK(not p.is_absolute());
+        // absolute is called recursivly on base. The following conditions
+        // must be true for it to return base unmodified
+        TEST_REQUIRE(base.has_root_name());
+        TEST_REQUIRE(base.has_root_directory());
+        path ret = absolute(p, base);
+        const path expect("//net/foo/bar");
+        TEST_CHECK(ret.is_absolute());
+        TEST_CHECK(ret == path("//net/foo/bar"));
+    }
+    // !has_root_name() && !has_root_directory()
+    {
+        const path p("bar/baz");
+        const path base("//net/foo");
+        TEST_REQUIRE(not p.has_root_name());
+        TEST_REQUIRE(not p.has_root_directory());
+        TEST_REQUIRE(base.has_root_name());
+        TEST_REQUIRE(base.has_root_directory());
+
+        path ret = absolute(p, base);
+        TEST_CHECK(ret.is_absolute());
+        TEST_CHECK(ret == path("//net/foo/bar/baz"));
+    }
+}
+
+TEST_CASE(absolute_path_with_default_base)
+{
+    const path testCases[] = {
+        "//net/foo", //  has_root_name() &&  has_root_directory()
+        "/foo",      // !has_root_name() &&  has_root_directory()
+        "//net",     //  has_root_name() && !has_root_directory()
+        "bar/baz"    // !has_root_name() && !has_root_directory()
+    };
+    const path base = current_path();
+    for (auto& p : testCases) {
+        const path ret = absolute(p);
+        const path expect = absolute(p, base);
+        TEST_CHECK(ret.is_absolute());
+        TEST_CHECK(ret == expect);
+    }
+}
+
+TEST_SUITE_END()

+ 118 - 0
test/std/experimental/filesystem/fs.op.funcs/fs.op.canonical/canonical.pass.cpp

@@ -0,0 +1,118 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// path canonical(const path& p, const path& base = current_path());
+// path canonical(const path& p, error_code& ec);
+// path canonical(const path& p, const path& base, error_code& ec);
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+
+TEST_SUITE(filesystem_canonical_path_test_suite)
+
+TEST_CASE(signature_test)
+{
+    const path p; ((void)p);
+    std::error_code ec; ((void)ec);
+    ASSERT_NOT_NOEXCEPT(canonical(p));
+    ASSERT_NOT_NOEXCEPT(canonical(p, p));
+    ASSERT_NOT_NOEXCEPT(canonical(p, ec));
+    ASSERT_NOT_NOEXCEPT(canonical(p, p, ec));
+}
+
+// There are 4 cases is the proposal for absolute path.
+// Each scope tests one of the cases.
+TEST_CASE(test_canonical)
+{
+    // has_root_name() && has_root_directory()
+    const path Root = StaticEnv::Root;
+    const path RootName = Root.filename();
+    const path DirName = StaticEnv::Dir.filename();
+    const path SymlinkName = StaticEnv::SymlinkToFile.filename();
+    struct TestCase {
+        path p;
+        path expect;
+        path base = StaticEnv::Root;
+    };
+    const TestCase testCases[] = {
+        { ".", Root, Root},
+        { DirName / ".." / "." / DirName, StaticEnv::Dir, Root},
+        { StaticEnv::Dir2 / "..",    StaticEnv::Dir },
+        { StaticEnv::Dir3 / "../..", StaticEnv::Dir },
+        { StaticEnv::Dir / ".",      StaticEnv::Dir },
+        { Root / "." / DirName / ".." / DirName, StaticEnv::Dir},
+        { path("..") / "." / RootName / DirName / ".." / DirName, StaticEnv::Dir, Root},
+        { StaticEnv::SymlinkToFile,  StaticEnv::File },
+        { SymlinkName, StaticEnv::File, StaticEnv::Root}
+    };
+    for (auto& TC : testCases) {
+        std::error_code ec;
+        const path ret = canonical(TC.p, TC.base, ec);
+        TEST_REQUIRE(!ec);
+        const path ret2 = canonical(TC.p, TC.base);
+        TEST_CHECK(ret == TC.expect);
+        TEST_CHECK(ret == ret2);
+        TEST_CHECK(ret.is_absolute());
+    }
+}
+
+TEST_CASE(test_dne_path)
+{
+    std::error_code ec;
+    {
+        const path ret = canonical(StaticEnv::DNE, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(ret == path{});
+    }
+    ec.clear();
+    {
+        const path ret = canonical(StaticEnv::DNE, StaticEnv::Root, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(ret == path{});
+    }
+    {
+        TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE));
+        TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE, StaticEnv::Root));
+    }
+}
+
+TEST_CASE(test_exception_contains_paths)
+{
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    const path p = "blabla/dne";
+    const path base = StaticEnv::Root;
+    try {
+        canonical(p, base);
+        TEST_REQUIRE(false);
+    } catch (filesystem_error const& err) {
+        TEST_CHECK(err.path1() == p);
+        TEST_CHECK(err.path2() == base);
+    }
+    try {
+        canonical(p);
+        TEST_REQUIRE(false);
+    } catch (filesystem_error const& err) {
+        TEST_CHECK(err.path1() == p);
+        TEST_CHECK(err.path2() == current_path());
+    }
+#endif
+}
+
+TEST_SUITE_END()

+ 251 - 0
test/std/experimental/filesystem/fs.op.funcs/fs.op.copy/copy.pass.cpp

@@ -0,0 +1,251 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/filesystem>
+
+// void copy(const path& from, const path& to);
+// void copy(const path& from, const path& to, error_code& ec) noexcept;
+// void copy(const path& from, const path& to, copy_options options);
+// void copy(const path& from, const path& to, copy_options options,
+//           error_code& ec) noexcept;
+
+#include <experimental/filesystem>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "rapid-cxx-test.hpp"
+#include "filesystem_test_helper.hpp"
+
+using namespace std::experimental::filesystem;
+namespace fs = std::experimental::filesystem;
+
+using CO = fs::copy_options;
+
+TEST_SUITE(filesystem_copy_test_suite)
+
+TEST_CASE(signature_test)
+{
+    const path p; ((void)p);
+    std::error_code ec; ((void)ec);
+    const copy_options opts{}; ((void)opts);
+    ASSERT_NOT_NOEXCEPT(fs::copy(p, p));
+    ASSERT_NOEXCEPT(fs::copy(p, p, ec));
+    ASSERT_NOT_NOEXCEPT(copy(p, p, opts));
+    ASSERT_NOEXCEPT(copy(p, p, opts, ec));
+}
+
+// There are 4 cases is the proposal for absolute path.
+// Each scope tests one of the cases.
+TEST_CASE(test_error_reporting)
+{
+    auto checkThrow = [](path const& f, path const& t, const std::error_code& ec)
+    {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+        try {
+            fs::copy(f, t);
+            return false;
+        } catch (filesystem_error const& err) {
+            return err.path1() == f
+                && err.path2() == t
+                && err.code() == ec;
+        }
+#else
+        return true;
+#endif
+    };
+
+    scoped_test_env env;
+    const path file = env.create_file("file1", 42);
+    const path dir = env.create_dir("dir");
+    const path fifo = env.create_fifo("fifo");
+    TEST_REQUIRE(is_other(fifo));
+
+    // !exists(f)
+    {
+        std::error_code ec;
+        const path f = StaticEnv::DNE;
+        const path t = env.test_root;
+        fs::copy(f, t, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(checkThrow(f, t, ec));
+    }
+    { // equivalent(f, t) == true
+        std::error_code ec;
+        fs::copy(file, file, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(checkThrow(file, file, ec));
+    }
+    { // is_directory(from) && is_file(to)
+        std::error_code ec;
+        fs::copy(dir, file, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(checkThrow(dir, file, ec));
+    }
+    { // is_other(from)
+        std::error_code ec;
+        fs::copy(fifo, dir, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(checkThrow(fifo, dir, ec));
+    }
+    { // is_other(to)
+        std::error_code ec;
+        fs::copy(file, fifo, ec);
+        TEST_REQUIRE(ec);
+        TEST_CHECK(checkThrow(file, fifo, ec));
+    }
+}
+
+TEST_CASE(from_is_symlink)
+{
+    scoped_test_env env;
+    const path file = env.create_file("file", 42);
+    const path symlink = env.create_symlink(file, "sym");
+    const path dne = env.make_env_path("dne");
+
+    { // skip symlinks
+        std::error_code ec;
+        fs::copy(symlink, dne, copy_options::skip_symlinks, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(!exists(dne));
+    }
+    {
+        const path dest = env.make_env_path("dest");
+        std::error_code ec;
+        fs::copy(symlink, dest, copy_options::copy_symlinks, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(exists(dest));
+        TEST_CHECK(is_symlink(dest));
+    }
+    { // copy symlink but target exists
+        std::error_code ec;
+        fs::copy(symlink, file, copy_options::copy_symlinks, ec);
+        TEST_CHECK(ec);
+    }
+    { // create symlinks but target exists
+        std::error_code ec;
+        fs::copy(symlink, file, copy_options::create_symlinks, ec);
+        TEST_CHECK(ec);
+    }
+}
+
+TEST_CASE(from_is_regular_file)
+{
+    scoped_test_env env;
+    const path file = env.create_file("file", 42);
+    const path dir = env.create_dir("dir");
+    { // skip copy because of directory
+        const path dest = env.make_env_path("dest1");
+        std::error_code ec;
+        fs::copy(file, dest, CO::directories_only, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(!exists(dest));
+    }
+    { // create symlink to file
+        const path dest = env.make_env_path("sym");
+        std::error_code ec;
+        fs::copy(file, dest, CO::create_symlinks, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(is_symlink(dest));
+        TEST_CHECK(equivalent(file, canonical(dest)));
+    }
+    { // create hard link to file
+        const path dest = env.make_env_path("hardlink");
+        TEST_CHECK(hard_link_count(file) == 1);
+        std::error_code ec;
+        fs::copy(file, dest, CO::create_hard_links, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(exists(dest));
+        TEST_CHECK(hard_link_count(file) == 2);
+    }
+    { // is_directory(t)
+        const path dest_dir = env.create_dir("dest_dir");
+        const path expect_dest = dest_dir / file.filename();
+        std::error_code ec;
+        fs::copy(file, dest_dir, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(is_regular_file(expect_dest));
+    }
+    { // otherwise copy_file(from, to, ...)
+        const path dest = env.make_env_path("file_copy");
+        std::error_code ec;
+        fs::copy(file, dest, ec);
+        TEST_CHECK(!ec);
+        TEST_CHECK(is_regular_file(dest));
+    }
+}
+
+TEST_CASE(from_is_directory)
+{
+    struct FileInfo {
+        path filename;
+        int size;
+    };
+    const FileInfo files[] = {
+        {"file1", 0},
+        {"file2", 42},
+        {"file3", 300}
+    };
+    scoped_test_env env;
+    const path dir = env.create_dir("dir");
+    const path nested_dir_name = "dir2";
+    const path nested_dir = env.create_dir("dir/dir2");
+
+    for (auto& FI : files) {
+        env.create_file(dir / FI.filename, FI.size);
+        env.create_file(nested_dir / FI.filename, FI.size);
+    }
+    { // test for non-existant directory
+        const path dest = env.make_env_path("dest_dir1");
+        std::error_code ec;
+        fs::copy(dir, dest, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(is_directory(dest));
+        for (auto& FI : files) {
+            path created = dest / FI.filename;
+            TEST_CHECK(is_regular_file(created));
+            TEST_CHECK(file_size(created) == FI.size);
+        }
+        TEST_CHECK(!is_directory(dest / nested_dir_name));
+    }
+    { // test for existing directory
+        const path dest = env.create_dir("dest_dir2");
+        std::error_code ec;
+        fs::copy(dir, dest, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(is_directory(dest));
+        for (auto& FI : files) {
+            path created = dest / FI.filename;
+            TEST_CHECK(is_regular_file(created));
+            TEST_CHECK(file_size(created) == FI.size);
+        }
+        TEST_CHECK(!is_directory(dest / nested_dir_name));
+    }
+    { // test recursive copy
+        const path dest = env.make_env_path("dest_dir3");
+        std::error_code ec;
+        fs::copy(dir, dest, CO::recursive, ec);
+        TEST_REQUIRE(!ec);
+        TEST_CHECK(is_directory(dest));
+        const path nested_dest = dest / nested_dir_name;
+        TEST_REQUIRE(is_directory(nested_dest));
+        for (auto& FI : files) {
+            path created = dest / FI.filename;
+            path nested_created = nested_dest / FI.filename;
+            TEST_CHECK(is_regular_file(created));
+            TEST_CHECK(file_size(created) == FI.size);
+            TEST_CHECK(is_regular_file(nested_created));
+            TEST_CHECK(file_size(nested_created) == FI.size);
+        }
+    }
+
+}
+TEST_SUITE_END()

Some files were not shown because too many files changed in this diff