<div dir="ltr">Hi Eric,<div>Looks like this commit caused a test failure on Green Dragon in libc++.std/experimental/filesystem/fs_op_funcs/fs_op_proximate.proximate.pass.cpp.  The test result from the build may be found here:</div><div><a href="http://green.lab.llvm.org/green/job/libcxx_master_cmake_32/2643/testReport/junit/libc++/std_experimental_filesystem_fs_op_funcs_fs_op_proximate/proximate_pass_cpp/">http://green.lab.llvm.org/green/job/libcxx_master_cmake_32/2643/testReport/junit/libc++/std_experimental_filesystem_fs_op_funcs_fs_op_proximate/proximate_pass_cpp/</a><br></div><div><br></div><div>Would you please have a look and either revert the commit or let me know if a patch will be committed within the next hour?</div><div><br></div><div>Respectfully,</div><div>Mike Edwards</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 2, 2018 at 4:03 PM, Eric Fiselier via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ericwf<br>
Date: Mon Apr  2 16:03:41 2018<br>
New Revision: 329028<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=329028&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=329028&view=rev</a><br>
Log:<br>
Implement filesystem NB comments, relative paths, and related issues.<br>
<br>
This is a fairly large patch that implements all of the filesystem NB comments<br>
and the relative paths changes (ex. adding weakly_canonical). These issues<br>
and papers are all interrelated so their implementation couldn't be split up<br>
nicely.<br>
<br>
This patch upgrades <experimental/filesystem> to match the C++17 spec and not<br>
the published experimental TS spec. Some of the changes in this patch are both<br>
API and ABI breaking, however libc++ makes no guarantee about stability for<br>
experimental implementations.<br>
<br>
The major changes in this patch are:<br>
<br>
* Implement NB comments for filesystem (P0492R2), including:<br>
  * Implement `perm_options` enum as part of NB comments, and update the<br>
    `permissions` function to match.<br>
  * Implement changes to `remove_filename` and `replace_filename`<br>
  * Implement changes to `path::stem()` and `path::extension()` which support<br>
    splitting examples like `.profile`.<br>
  * Change path iteration to return an empty path instead of '.' for trailing<br>
    separators.<br>
  * Change `operator/=` to handle absolute paths on the RHS.<br>
  * Change `absolute` to no longer accept a current path argument.<br>
<br>
* Implement relative paths according to NB comments (P0219r1)<br>
<br>
* Combine `path.cpp` and `operations.cpp` since some path functions require<br>
  access to the operations internals, and some fs operations require access<br>
  to the path parser.<br>
<br>
Added:<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_normal.pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_relative_and_<wbr>proximate.pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.<wbr>enum/enum.perm_options.pass.<wbr>cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<wbr>proximate.pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/relative.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<wbr>weakly_canonical.pass.cpp<br>
    libcxx/trunk/test/support/<wbr>verbose_assert.h<br>
Removed:<br>
    libcxx/trunk/src/experimental/<wbr>filesystem/path.cpp<br>
    libcxx/trunk/test/libcxx/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.system_complete/<wbr>system_complete.pass.cpp<br>
Modified:<br>
    libcxx/trunk/benchmarks/<wbr>CMakeLists.txt<br>
    libcxx/trunk/benchmarks/<wbr>GenerateInput.hpp<br>
    libcxx/trunk/benchmarks/<wbr>filesystem.bench.cpp<br>
    libcxx/trunk/include/<wbr>experimental/filesystem<br>
    libcxx/trunk/src/experimental/<wbr>filesystem/operations.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.itr/iterator.pass.<wbr>cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.compare.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/empty.fail.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/path.decompose.pass.<wbr>cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/generic_string_alloc.pass.<wbr>cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/named_overloads.pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/remove_filename.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/replace_filename.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.absolute/absolute.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.canonical/<wbr>canonical.pass.cpp<br>
    libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.last_write_time/<wbr>last_write_time.pass.cpp<br>
    libcxx/trunk/test/support/<wbr>filesystem_test_helper.hpp<br>
    libcxx/trunk/www/cxx1z_status.<wbr>html<br>
    libcxx/trunk/www/cxx2a_status.<wbr>html<br>
<br>
Modified: libcxx/trunk/benchmarks/<wbr>CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/CMakeLists.txt?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/<wbr>benchmarks/CMakeLists.txt?rev=<wbr>329028&r1=329027&r2=329028&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/benchmarks/<wbr>CMakeLists.txt (original)<br>
+++ libcxx/trunk/benchmarks/<wbr>CMakeLists.txt Mon Apr  2 16:03:41 2018<br>
@@ -68,7 +68,7 @@ set(BENCHMARK_OUTPUT_DIR ${CMAKE_CURRENT<br>
 set(BENCHMARK_LIBCXX_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/<wbr>benchmark-libcxx)<br>
 set(BENCHMARK_NATIVE_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/<wbr>benchmark-native)<br>
 set(BENCHMARK_TEST_COMPILE_<wbr>FLAGS<br>
-    -std=c++14 -O2<br>
+    -std=c++17 -O2<br>
     -I${BENCHMARK_LIBCXX_INSTALL}/<wbr>include<br>
     -I${LIBCXX_SOURCE_DIR}/test/<wbr>support<br>
 )<br>
<br>
Modified: libcxx/trunk/benchmarks/<wbr>GenerateInput.hpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/GenerateInput.hpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/<wbr>benchmarks/GenerateInput.hpp?<wbr>rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/benchmarks/<wbr>GenerateInput.hpp (original)<br>
+++ libcxx/trunk/benchmarks/<wbr>GenerateInput.hpp Mon Apr  2 16:03:41 2018<br>
@@ -29,14 +29,16 @@ inline std::default_random_engine& getRa<br>
     return RandEngine;<br>
 }<br>
<br>
+<br>
 inline char getRandomChar() {<br>
     std::uniform_int_distribution<<wbr>> LettersDist(0, LettersSize-1);<br>
     return Letters[LettersDist(<wbr>getRandomEngine())];<br>
 }<br>
<br>
 template <class IntT><br>
-inline IntT getRandomInteger() {<br>
-    std::uniform_int_distribution<<wbr>IntT> dist;<br>
+inline IntT getRandomInteger(IntT Min = 0,<br>
+                             IntT Max = std::numeric_limits<IntT>::<wbr>max()) {<br>
+    std::uniform_int_distribution<<wbr>IntT> dist(Min, Max);<br>
     return dist(getRandomEngine());<br>
 }<br>
<br>
<br>
Modified: libcxx/trunk/benchmarks/<wbr>filesystem.bench.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/filesystem.bench.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/<wbr>benchmarks/filesystem.bench.<wbr>cpp?rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/benchmarks/<wbr>filesystem.bench.cpp (original)<br>
+++ libcxx/trunk/benchmarks/<wbr>filesystem.bench.cpp Mon Apr  2 16:03:41 2018<br>
@@ -1,17 +1,14 @@<br>
-#include <experimental/filesystem><br>
-<br>
 #include "benchmark/benchmark.h"<br>
 #include "GenerateInput.hpp"<br>
 #include "test_iterators.h"<br>
-<br>
-namespace fs = std::experimental::filesystem;<br>
+#include "filesystem_include.hpp"<br>
<br>
 static const size_t TestNumInputs = 1024;<br>
<br>
<br>
 template <class GenInputs><br>
 void BM_PathConstructString(<wbr>benchmark::State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
   for (auto& Part : in)<br>
@@ -21,14 +18,15 @@ void BM_PathConstructString(<wbr>benchmark::S<br>
     const path P(PP.native());<br>
     benchmark::DoNotOptimize(P.<wbr>native().data());<br>
   }<br>
+  st.SetComplexityN(st.range(0))<wbr>;<br>
 }<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathConstructString, large_string,<br>
-  getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
+  getRandomStringInputs)->Range(<wbr>8, TestNumInputs)->Complexity();<br>
<br>
<br>
 template <class GenInputs><br>
 void BM_PathConstructCStr(<wbr>benchmark::State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
   for (auto& Part : in)<br>
@@ -45,7 +43,7 @@ BENCHMARK_CAPTURE(BM_<wbr>PathConstructCStr,<br>
<br>
 template <template <class...> class ItType, class GenInputs><br>
 void BM_PathConstructIter(<wbr>benchmark::State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   using Iter = ItType<std::string::const_<wbr>iterator>;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
@@ -60,6 +58,7 @@ void BM_PathConstructIter(<wbr>benchmark::Sta<br>
     const path P(Start, End);<br>
     benchmark::DoNotOptimize(P.<wbr>native().data());<br>
   }<br>
+  st.SetComplexityN(st.range(0))<wbr>;<br>
 }<br>
 template <class GenInputs><br>
 void BM_PathConstructInputIter(<wbr>benchmark::State &st, GenInputs gen) {<br>
@@ -70,14 +69,14 @@ void BM_PathConstructForwardIter(<wbr>benchma<br>
   BM_PathConstructIter<forward_<wbr>iterator>(st, gen);<br>
 }<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathConstructInputIter, large_string,<br>
-  getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
+  getRandomStringInputs)->Range(<wbr>8, TestNumInputs)->Complexity();<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathConstructForwardIter, large_string,<br>
-  getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
+  getRandomStringInputs)->Range(<wbr>8, TestNumInputs)->Complexity();<br>
<br>
<br>
 template <class GenInputs><br>
 void BM_PathIterateMultipleTimes(<wbr>benchmark::State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
   for (auto& Part : in)<br>
@@ -89,14 +88,15 @@ void BM_PathIterateMultipleTimes(<wbr>benchma<br>
     }<br>
     benchmark::ClobberMemory();<br>
   }<br>
+  st.SetComplexityN(st.range(0))<wbr>;<br>
 }<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathIterateMultipleTimes, iterate_elements,<br>
-  getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
+  getRandomStringInputs)->Range(<wbr>8, TestNumInputs)->Complexity();<br>
<br>
<br>
 template <class GenInputs><br>
 void BM_PathIterateOnce(benchmark::<wbr>State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
   for (auto& Part : in)<br>
@@ -109,13 +109,14 @@ void BM_PathIterateOnce(benchmark::<wbr>State<br>
     }<br>
     benchmark::ClobberMemory();<br>
   }<br>
+  st.SetComplexityN(st.range(0))<wbr>;<br>
 }<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathIterateOnce, iterate_elements,<br>
-  getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
+  getRandomStringInputs)->Range(<wbr>8, TestNumInputs)->Complexity();<br>
<br>
 template <class GenInputs><br>
 void BM_PathIterateOnceBackwards(<wbr>benchmark::State &st, GenInputs gen) {<br>
-  using namespace fs;<br>
+  using fs::path;<br>
   const auto in = gen(st.range(0));<br>
   path PP;<br>
   for (auto& Part : in)<br>
@@ -135,4 +136,28 @@ void BM_PathIterateOnceBackwards(<wbr>benchma<br>
 BENCHMARK_CAPTURE(BM_<wbr>PathIterateOnceBackwards, iterate_elements,<br>
   getRandomStringInputs)->Arg(<wbr>TestNumInputs);<br>
<br>
+static fs::path getRandomPaths(int NumParts, int PathLen) {<br>
+  fs::path Result;<br>
+  while (NumParts--) {<br>
+    std::string Part = getRandomString(PathLen);<br>
+    Result /= Part;<br>
+  }<br>
+  return Result;<br>
+}<br>
+<br>
+template <class GenInput><br>
+void BM_LexicallyNormal(benchmark::<wbr>State &st, GenInput gen, size_t PathLen) {<br>
+  using fs::path;<br>
+  auto In = gen(st.range(0), PathLen);<br>
+  benchmark::DoNotOptimize(&In);<br>
+  while (st.KeepRunning()) {<br>
+    benchmark::DoNotOptimize(In.<wbr>lexically_normal());<br>
+  }<br>
+  st.SetComplexityN(st.range(0))<wbr>;<br>
+}<br>
+BENCHMARK_CAPTURE(BM_<wbr>LexicallyNormal, small_path,<br>
+  getRandomPaths, /*PathLen*/5)-><wbr>RangeMultiplier(2)->Range(2, 256)->Complexity();<br>
+BENCHMARK_CAPTURE(BM_<wbr>LexicallyNormal, large_path,<br>
+  getRandomPaths, /*PathLen*/32)-><wbr>RangeMultiplier(2)->Range(2, 256)->Complexity();<br>
+<br>
 BENCHMARK_MAIN();<br>
<br>
Modified: libcxx/trunk/include/<wbr>experimental/filesystem<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/filesystem?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/include/<wbr>experimental/filesystem?rev=<wbr>329028&r1=329027&r2=329028&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/include/<wbr>experimental/filesystem (original)<br>
+++ libcxx/trunk/include/<wbr>experimental/filesystem Mon Apr  2 16:03:41 2018<br>
@@ -76,11 +76,11 @@<br>
<br>
     // operational functions<br>
<br>
-    path absolute(const path& p, const path& base=current_path());<br>
+    path absolute(const path& p);<br>
+    path absolute(const path& p, error_code &ec);<br>
<br>
-    path canonical(const path& p, const path& base = current_path());<br>
+    path canonical(const path& p);<br>
     path canonical(const path& p, error_code& ec);<br>
-    path canonical(const path& p, const path& base, error_code& ec);<br>
<br>
     void copy(const path& from, const path& to);<br>
     void copy(const path& from, const path& to, error_code& ec);<br>
@@ -185,9 +185,17 @@<br>
     void permissions(const path& p, perms prms, perm_options opts,<br>
                      error_code& ec);<br>
<br>
+    path proximate(const path& p, error_code& ec);<br>
+    path proximate(const path& p, const path& base = current_path());<br>
+    path proximate(const path& p, const path& base, error_code &ec);<br>
+<br>
     path read_symlink(const path& p);<br>
     path read_symlink(const path& p, error_code& ec);<br>
<br>
+    path relative(const path& p, error_code& ec);<br>
+    path relative(const path& p, const path& base=current_path());<br>
+    path relative(const path& p, const path& base, error_code& ec);<br>
+<br>
     bool remove(const path& p);<br>
     bool remove(const path& p, error_code& ec) _NOEXCEPT;<br>
<br>
@@ -211,12 +219,13 @@<br>
     file_status  symlink_status(const path& p);<br>
     file_status  symlink_status(const path& p, error_code& ec) _NOEXCEPT;<br>
<br>
-    path system_complete(const path& p);<br>
-    path system_complete(const path& p, error_code& ec);<br>
-<br>
     path temp_directory_path();<br>
     path temp_directory_path(error_<wbr>code& ec);<br>
<br>
+    path weakly_canonical(path const& p);<br>
+    path weakly_canonical(path const& p, error_code& ec);<br>
+<br>
+<br>
 } } } }  // namespaces std::experimental::filesystem:<wbr>:v1<br>
<br>
 */<br>
@@ -796,26 +805,26 @@ public:<br>
<br>
 private:<br>
     template <class _ECharT><br>
-    void __append_sep_if_needed(_ECharT __first_or_null) {<br>
-        const _ECharT __null_val = {};<br>
-        bool __append_sep = !empty()                       &&<br>
-                            !__is_separator(__pn_.back())  &&<br>
-                            __first_or_null != __null_val  && // non-empty<br>
-                            !__is_separator(__first_or_<wbr>null);<br>
-        if (__append_sep)<br>
-            __pn_ += preferred_separator;<br>
+    static bool __source_is_absolute(_ECharT __first_or_null) {<br>
+        return __is_separator(__first_or_<wbr>null);<br>
     }<br>
<br>
 public:<br>
     // appends<br>
     path& operator/=(const path& __p) {<br>
-        _LIBCPP_ASSERT(!__p.has_root_<wbr>name(),<br>
-                      "cannot append to a path with a root name");<br>
-        __append_sep_if_needed(__p.<wbr>empty() ? char{} : __p.__pn_[0]);<br>
+        if (__p.is_absolute()) {<br>
+          __pn_ = __p.__pn_;<br>
+          return *this;<br>
+        }<br>
+        if (has_filename())<br>
+          __pn_ += preferred_separator;<br>
         __pn_ += __p.native();<br>
         return *this;<br>
     }<br>
<br>
+    // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src<br>
+    // is known at compile time to be "/' since the user almost certainly intended<br>
+    // to append a separator instead of overwriting the path with "/"<br>
     template <class _Source><br>
     _LIBCPP_INLINE_VISIBILITY<br>
     _EnableIfPathable<_Source><br>
@@ -828,7 +837,10 @@ public:<br>
     append(const _Source& __src) {<br>
         using _Traits = __is_pathable<_Source>;<br>
         using _CVT = _PathCVT<_SourceChar<_Source>><wbr>;<br>
-        __append_sep_if_needed(_<wbr>Traits::__first_or_null(__src)<wbr>);<br>
+        if (__source_is_absolute(_Traits:<wbr>:__first_or_null(__src)))<br>
+          __pn_.clear();<br>
+        else if (has_filename())<br>
+          __pn_ += preferred_separator;<br>
         _CVT::__append_source(__pn_, __src);<br>
         return *this;<br>
     }<br>
@@ -838,10 +850,11 @@ public:<br>
         typedef typename iterator_traits<_InputIt>::<wbr>value_type _ItVal;<br>
         static_assert(__can_convert_<wbr>char<_ItVal>::value, "Must convertible");<br>
         using _CVT = _PathCVT<_ItVal>;<br>
-        if (__first != __last) {<br>
-            __append_sep_if_needed(*__<wbr>first);<br>
-            _CVT::__append_range(__pn_, __first, __last);<br>
-        }<br>
+        if (__first != __last && __source_is_absolute(*__first)<wbr>)<br>
+          __pn_.clear();<br>
+        else if (has_filename())<br>
+          __pn_ += preferred_separator;<br>
+        _CVT::__append_range(__pn_, __first, __last);<br>
         return *this;<br>
     }<br>
<br>
@@ -916,10 +929,9 @@ public:<br>
<br>
     _LIBCPP_INLINE_VISIBILITY<br>
     path& remove_filename() {<br>
-      if (__pn_.size() == __root_path_raw().size())<br>
-        clear();<br>
-      else<br>
-        __pn_ = __parent_path();<br>
+      auto __fname = __filename();<br>
+      if (!__fname.empty())<br>
+        __pn_.erase(__fname.data() - __pn_.data());<br>
       return *this;<br>
     }<br>
<br>
@@ -935,6 +947,10 @@ public:<br>
         __pn_.swap(__rhs.__pn_);<br>
     }<br>
<br>
+    // private helper to allow reserving memory in the path<br>
+    _LIBCPP_INLINE_VISIBILITY<br>
+    void __reserve(size_t __s) { __pn_.reserve(__s); }<br>
+<br>
     // native format observers<br>
     _LIBCPP_INLINE_VISIBILITY<br>
     const string_type& native() const _NOEXCEPT {<br>
@@ -1023,6 +1039,17 @@ public:<br>
     _LIBCPP_INLINE_VISIBILITY bool is_absolute()        const { return has_root_directory(); }<br>
     _LIBCPP_INLINE_VISIBILITY bool is_relative()        const { return !is_absolute(); }<br>
<br>
+    // relative paths<br>
+    path lexically_normal() const;<br>
+    path lexically_relative(const path& __base) const;<br>
+<br>
+    _LIBCPP_INLINE_VISIBILITY path lexically_proximate(const path& __base) const {<br>
+      path __result = this->lexically_relative(__<wbr>base);<br>
+      if (__result.native().empty())<br>
+        return *this;<br>
+      return __result;<br>
+    }<br>
+<br>
     // iterators<br>
     class _LIBCPP_TYPE_VIS iterator;<br>
     typedef iterator const_iterator;<br>
@@ -1277,7 +1304,9 @@ void __throw_filesystem_error(_<wbr>Args&&...<br>
 // operational functions<br>
<br>
 _LIBCPP_FUNC_VIS<br>
-path __canonical(const path&, const path&, error_code *__ec=nullptr);<br>
+path __absolute(const path&, error_code *__ec=nullptr);<br>
+_LIBCPP_FUNC_VIS<br>
+path __canonical(const path&, error_code *__ec=nullptr);<br>
 _LIBCPP_FUNC_VIS<br>
 void __copy(const path& __from, const path& __to, copy_options __opt,<br>
         error_code *__ec=nullptr);<br>
@@ -1342,6 +1371,8 @@ _LIBCPP_FUNC_VIS<br>
 path __system_complete(const path&, error_code *__ec=nullptr);<br>
 _LIBCPP_FUNC_VIS<br>
 path __temp_directory_path(error_<wbr>code *__ec=nullptr);<br>
+_LIBCPP_FUNC_VIS<br>
+path __weakly_canonical(path const& __p, error_code *__ec=nullptr);<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
 path current_path() {<br>
@@ -1363,24 +1394,24 @@ void current_path(const path& __p, error<br>
     __current_path(__p, &__ec);<br>
 }<br>
<br>
-_LIBCPP_FUNC_VIS<br>
-path absolute(const path&, const path& __p2 = current_path());<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path absolute(const path& __p) {<br>
+  return __absolute(__p);<br>
+}<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path canonical(const path& __p, const path& __base = current_path()) {<br>
-    return __canonical(__p, __base);<br>
+path absolute(const path& __p, error_code &__ec) {<br>
+  return __absolute(__p, &__ec);<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path canonical(const path& __p, error_code& __ec) {<br>
-    path __base = __current_path(&__ec);<br>
-    if (__ec) return {};<br>
-    return __canonical(__p, __base, &__ec);<br>
+path canonical(const path& __p) {<br>
+    return __canonical(__p);<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path canonical(const path& __p, const path& __base, error_code& __ec) {<br>
-    return __canonical(__p, __base, &__ec);<br>
+path canonical(const path& __p, error_code& __ec) {<br>
+    return __canonical(__p, &__ec);<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
@@ -1492,7 +1523,8 @@ void create_symlink(const path& __to, co<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-void create_symlink(const path& __to, const path& __new, error_code& __ec) _NOEXCEPT {<br>
+void create_symlink(const path& __to, const path& __new,<br>
+                    error_code& __ec) _NOEXCEPT {<br>
     return __create_symlink(__to, __new, &__ec);<br>
 }<br>
<br>
@@ -1716,6 +1748,27 @@ void permissions(const path& __p, perms<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
+path proximate(const path& __p, const path& __base, error_code& __ec) {<br>
+   path __tmp = __weakly_canonical(__p, &__ec);<br>
+  if (__ec)<br>
+    return {};<br>
+  path __tmp_base = __weakly_canonical(__base, &__ec);<br>
+  if (__ec)<br>
+    return {};<br>
+  return __tmp.lexically_proximate(__<wbr>tmp_base);<br>
+}<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path proximate(const path& __p, error_code& __ec) {<br>
+  return proximate(__p, current_path(), __ec);<br>
+}<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path proximate(const path& __p, const path& __base = current_path()) {<br>
+  return __weakly_canonical(__p).<wbr>lexically_proximate(__weakly_<wbr>canonical(__base));<br>
+}<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
 path read_symlink(const path& __p) {<br>
     return __read_symlink(__p);<br>
 }<br>
@@ -1725,6 +1778,29 @@ path read_symlink(const path& __p, error<br>
     return __read_symlink(__p, &__ec);<br>
 }<br>
<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path relative(const path& __p, const path& __base, error_code& __ec) {<br>
+  path __tmp = __weakly_canonical(__p, &__ec);<br>
+  if (__ec)<br>
+    return path();<br>
+  path __tmpbase = __weakly_canonical(__base, &__ec);<br>
+  if (__ec)<br>
+    return path();<br>
+  return __tmp.lexically_relative(__<wbr>tmpbase);<br>
+}<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path relative(const path& __p, error_code& __ec) {<br>
+  return relative(__p, current_path(), __ec);<br>
+}<br>
+<br>
+inline _LIBCPP_INLINE_VISIBILITY<br>
+path relative(const path& __p, const path& __base=current_path()) {<br>
+  return __weakly_canonical(__p).<wbr>lexically_relative(__weakly_<wbr>canonical(__base));<br>
+}<br>
+<br>
+<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
 bool remove(const path& __p) {<br>
     return __remove(__p);<br>
@@ -1796,23 +1872,23 @@ file_status symlink_status(const path& _<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path system_complete(const path& __p) {<br>
-    return __system_complete(__p);<br>
+path temp_directory_path() {<br>
+    return __temp_directory_path();<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path system_complete(const path& __p, error_code& __ec) {<br>
-    return __system_complete(__p, &__ec);<br>
+path temp_directory_path(error_<wbr>code& __ec) {<br>
+    return __temp_directory_path(&__ec);<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path temp_directory_path() {<br>
-    return __temp_directory_path();<br>
+path weakly_canonical(path const& __p) {<br>
+  return __weakly_canonical(__p);<br>
 }<br>
<br>
 inline _LIBCPP_INLINE_VISIBILITY<br>
-path temp_directory_path(error_<wbr>code& __ec) {<br>
-    return __temp_directory_path(&__ec);<br>
+path weakly_canonical(path const& __p, error_code& __ec) {<br>
+  return __weakly_canonical(__p, &__ec);<br>
 }<br>
<br>
<br>
<br>
Modified: libcxx/trunk/src/experimental/<wbr>filesystem/operations.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/operations.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/src/<wbr>experimental/filesystem/<wbr>operations.cpp?rev=329028&r1=<wbr>329027&r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/src/experimental/<wbr>filesystem/operations.cpp (original)<br>
+++ libcxx/trunk/src/experimental/<wbr>filesystem/operations.cpp Mon Apr  2 16:03:41 2018<br>
@@ -10,8 +10,10 @@<br>
 #include "experimental/filesystem"<br>
 #include "iterator"<br>
 #include "fstream"<br>
-#include "type_traits"<br>
 #include "random"  /* for unique_path */<br>
+#include "string_view"<br>
+#include "type_traits"<br>
+#include "vector"<br>
 #include "cstdlib"<br>
 #include "climits"<br>
<br>
@@ -57,6 +59,250 @@ _LIBCPP_BEGIN_NAMESPACE_<wbr>EXPERIMENTAL_FIL<br>
 filesystem_error::~filesystem_<wbr>error() {}<br>
<br>
<br>
+namespace { namespace parser<br>
+{<br>
+<br>
+using string_view_t = path::__string_view;<br>
+using string_view_pair = pair<string_view_t, string_view_t>;<br>
+using PosPtr = path::value_type const*;<br>
+<br>
+struct PathParser {<br>
+  enum ParserState : unsigned char {<br>
+    // Zero is a special sentinel value used by default constructed iterators.<br>
+    PS_BeforeBegin = 1,<br>
+    PS_InRootName,<br>
+    PS_InRootDir,<br>
+    PS_InFilenames,<br>
+    PS_InTrailingSep,<br>
+    PS_AtEnd<br>
+  };<br>
+<br>
+  const string_view_t Path;<br>
+  string_view_t RawEntry;<br>
+  ParserState State;<br>
+<br>
+private:<br>
+  PathParser(string_view_t P, ParserState State) noexcept<br>
+      : Path(P), State(State) {}<br>
+<br>
+public:<br>
+  PathParser(string_view_t P, string_view_t E, unsigned char S)<br>
+      : Path(P), RawEntry(E), State(static_cast<ParserState><wbr>(S)) {<br>
+    // S cannot be '0' or PS_BeforeBegin.<br>
+  }<br>
+<br>
+  static PathParser CreateBegin(string_view_t P) noexcept {<br>
+    PathParser PP(P, PS_BeforeBegin);<br>
+    PP.increment();<br>
+    return PP;<br>
+  }<br>
+<br>
+  static PathParser CreateEnd(string_view_t P) noexcept {<br>
+    PathParser PP(P, PS_AtEnd);<br>
+    return PP;<br>
+  }<br>
+<br>
+  PosPtr peek() const noexcept {<br>
+    auto TkEnd = getNextTokenStartPos();<br>
+    auto End = getAfterBack();<br>
+    return TkEnd == End ? nullptr : TkEnd;<br>
+  }<br>
+<br>
+  void increment() noexcept {<br>
+    const PosPtr End = getAfterBack();<br>
+    const PosPtr Start = getNextTokenStartPos();<br>
+    if (Start == End)<br>
+      return makeState(PS_AtEnd);<br>
+<br>
+    switch (State) {<br>
+    case PS_BeforeBegin: {<br>
+      PosPtr TkEnd = consumeSeparator(Start, End);<br>
+      if (TkEnd)<br>
+        return makeState(PS_InRootDir, Start, TkEnd);<br>
+      else<br>
+        return makeState(PS_InFilenames, Start, consumeName(Start, End));<br>
+    }<br>
+    case PS_InRootDir:<br>
+      return makeState(PS_InFilenames, Start, consumeName(Start, End));<br>
+<br>
+    case PS_InFilenames: {<br>
+      PosPtr SepEnd = consumeSeparator(Start, End);<br>
+      if (SepEnd != End) {<br>
+        PosPtr TkEnd = consumeName(SepEnd, End);<br>
+        if (TkEnd)<br>
+          return makeState(PS_InFilenames, SepEnd, TkEnd);<br>
+      }<br>
+      return makeState(PS_InTrailingSep, Start, SepEnd);<br>
+    }<br>
+<br>
+    case PS_InTrailingSep:<br>
+      return makeState(PS_AtEnd);<br>
+<br>
+    case PS_InRootName:<br>
+    case PS_AtEnd:<br>
+      _LIBCPP_UNREACHABLE();<br>
+    }<br>
+  }<br>
+<br>
+  void decrement() noexcept {<br>
+    const PosPtr REnd = getBeforeFront();<br>
+    const PosPtr RStart = getCurrentTokenStartPos() - 1;<br>
+    if (RStart == REnd) // we're decrementing the begin<br>
+      return makeState(PS_BeforeBegin);<br>
+<br>
+    switch (State) {<br>
+    case PS_AtEnd: {<br>
+      // Try to consume a trailing separator or root directory first.<br>
+      if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {<br>
+        if (SepEnd == REnd)<br>
+          return makeState(PS_InRootDir, Path.data(), RStart + 1);<br>
+        return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);<br>
+      } else {<br>
+        PosPtr TkStart = consumeName(RStart, REnd);<br>
+        return makeState(PS_InFilenames, TkStart + 1, RStart + 1);<br>
+      }<br>
+    }<br>
+    case PS_InTrailingSep:<br>
+      return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, RStart + 1);<br>
+    case PS_InFilenames: {<br>
+      PosPtr SepEnd = consumeSeparator(RStart, REnd);<br>
+      if (SepEnd == REnd)<br>
+        return makeState(PS_InRootDir, Path.data(), RStart + 1);<br>
+      PosPtr TkEnd = consumeName(SepEnd, REnd);<br>
+      return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);<br>
+    }<br>
+    case PS_InRootDir:<br>
+      // return makeState(PS_InRootName, Path.data(), RStart + 1);<br>
+    case PS_InRootName:<br>
+    case PS_BeforeBegin:<br>
+      _LIBCPP_UNREACHABLE();<br>
+    }<br>
+  }<br>
+<br>
+  /// \brief Return a view with the "preferred representation" of the current<br>
+  ///   element. For example trailing separators are represented as a '.'<br>
+  string_view_t operator*() const noexcept {<br>
+    switch (State) {<br>
+    case PS_BeforeBegin:<br>
+    case PS_AtEnd:<br>
+      return "";<br>
+    case PS_InRootDir:<br>
+      return "/";<br>
+    case PS_InTrailingSep:<br>
+      return "";<br>
+    case PS_InRootName:<br>
+    case PS_InFilenames:<br>
+      return RawEntry;<br>
+    }<br>
+    _LIBCPP_UNREACHABLE();<br>
+  }<br>
+<br>
+  explicit operator bool() const noexcept {<br>
+    return State != PS_BeforeBegin && State != PS_AtEnd;<br>
+  }<br>
+<br>
+  PathParser& operator++() noexcept {<br>
+    increment();<br>
+    return *this;<br>
+  }<br>
+<br>
+  PathParser& operator--() noexcept {<br>
+    decrement();<br>
+    return *this;<br>
+  }<br>
+<br>
+  bool inRootPath() const noexcept {<br>
+    return State == PS_InRootDir || State == PS_InRootName;<br>
+  }<br>
+<br>
+private:<br>
+  void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {<br>
+    State = NewState;<br>
+    RawEntry = string_view_t(Start, End - Start);<br>
+  }<br>
+  void makeState(ParserState NewState) noexcept {<br>
+    State = NewState;<br>
+    RawEntry = {};<br>
+  }<br>
+<br>
+  PosPtr getAfterBack() const noexcept {<br>
+    return Path.data() + Path.size();<br>
+  }<br>
+<br>
+  PosPtr getBeforeFront() const noexcept {<br>
+    return Path.data() - 1;<br>
+  }<br>
+<br>
+  /// \brief Return a pointer to the first character after the currently<br>
+  ///   lexed element.<br>
+  PosPtr getNextTokenStartPos() const noexcept {<br>
+    switch (State) {<br>
+    case PS_BeforeBegin:<br>
+      return Path.data();<br>
+    case PS_InRootName:<br>
+    case PS_InRootDir:<br>
+    case PS_InFilenames:<br>
+      return &RawEntry.back() + 1;<br>
+    case PS_InTrailingSep:<br>
+    case PS_AtEnd:<br>
+      return getAfterBack();<br>
+    }<br>
+    _LIBCPP_UNREACHABLE();<br>
+  }<br>
+<br>
+  /// \brief Return a pointer to the first character in the currently lexed<br>
+  ///   element.<br>
+  PosPtr getCurrentTokenStartPos() const noexcept {<br>
+    switch (State) {<br>
+    case PS_BeforeBegin:<br>
+    case PS_InRootName:<br>
+      return &Path.front();<br>
+    case PS_InRootDir:<br>
+    case PS_InFilenames:<br>
+    case PS_InTrailingSep:<br>
+      return &RawEntry.front();<br>
+    case PS_AtEnd:<br>
+      return &Path.back() + 1;<br>
+    }<br>
+    _LIBCPP_UNREACHABLE();<br>
+  }<br>
+<br>
+  PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {<br>
+    if (P == End || *P != '/')<br>
+      return nullptr;<br>
+    const int Inc = P < End ? 1 : -1;<br>
+    P += Inc;<br>
+    while (P != End && *P == '/')<br>
+      P += Inc;<br>
+    return P;<br>
+  }<br>
+<br>
+  PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {<br>
+    if (P == End || *P == '/')<br>
+      return nullptr;<br>
+    const int Inc = P < End ? 1 : -1;<br>
+    P += Inc;<br>
+    while (P != End && *P != '/')<br>
+      P += Inc;<br>
+    return P;<br>
+  }<br>
+};<br>
+<br>
+string_view_pair separate_filename(string_view_<wbr>t const & s) {<br>
+    if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};<br>
+    auto pos = s.find_last_of('.');<br>
+    if (pos == string_view_t::npos || pos == 0)<br>
+        return string_view_pair{s, string_view_t{}};<br>
+    return string_view_pair{s.substr(0, pos), s.substr(pos)};<br>
+}<br>
+<br>
+string_view_t createView(PosPtr S, PosPtr E) noexcept {<br>
+  return {S, static_cast<size_t>(E - S) + 1};<br>
+}<br>
+<br>
+}} // namespace parser<br>
+<br>
+<br>
 //                       POSIX HELPERS<br>
<br>
 namespace detail { namespace  {<br>
@@ -186,14 +432,33 @@ bool copy_file_impl(const path& from, co<br>
 }} // end namespace detail<br>
<br>
 using detail::set_or_throw;<br>
+using parser::string_view_t;<br>
+using parser::PathParser;<br>
+using parser::createView;<br>
+<br>
+static path __do_absolute(const path& p, path *cwd, std::error_code *ec) {<br>
+  if (ec) ec->clear();<br>
+    if (p.is_absolute())<br>
+      return p;<br>
+    *cwd = __current_path(ec);<br>
+    if (ec && *ec)<br>
+      return {};<br>
+    return (*cwd) / p;<br>
+}<br>
+<br>
+path __absolute(const path& p, std::error_code *ec) {<br>
+    path cwd;<br>
+    return __do_absolute(p, &cwd, ec);<br>
+}<br>
<br>
-path __canonical(path const & orig_p, const path& base, std::error_code *ec)<br>
+path __canonical(path const & orig_p, std::error_code *ec)<br>
 {<br>
-    path p = absolute(orig_p, base);<br>
+    path cwd;<br>
+    path p = __do_absolute(orig_p, &cwd, ec);<br>
     char buff[PATH_MAX + 1];<br>
     char *ret;<br>
     if ((ret = ::realpath(p.c_str(), buff)) == nullptr) {<br>
-        set_or_throw(ec, "canonical", orig_p, base);<br>
+        set_or_throw(ec, "canonical", orig_p, cwd);<br>
         return {};<br>
     }<br>
     if (ec) ec->clear();<br>
@@ -791,11 +1056,6 @@ file_status __symlink_status(const path&<br>
     return detail::posix_lstat(p, ec);<br>
 }<br>
<br>
-path __system_complete(const path& p, std::error_code *ec) {<br>
-    if (ec) ec->clear();<br>
-    return absolute(p, current_path());<br>
-}<br>
-<br>
 path __temp_directory_path(std::<wbr>error_code* ec) {<br>
   const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};<br>
   const char* ret = nullptr;<br>
@@ -820,34 +1080,393 @@ path __temp_directory_path(std::<wbr>error_co<br>
   return p;<br>
 }<br>
<br>
-// An absolute path is composed according to the table in [fs.op.absolute].<br>
-path absolute(const path& p, const path& base) {<br>
-    auto root_name = p.root_name();<br>
-    auto root_dir = p.root_directory();<br>
<br>
-    if (!root_name.empty() && !root_dir.empty())<br>
-      return p;<br>
+path __weakly_canonical(const path& p, std::error_code *ec) {<br>
+  if (p.empty())<br>
+    return __canonical("", ec);<br>
+<br>
+  path result;<br>
+  path tmp;<br>
+  tmp.__reserve(p.native().size(<wbr>));<br>
+  auto PP = PathParser::CreateEnd(p.<wbr>native());<br>
+  --PP;<br>
+  std::vector<string_view_t> DNEParts;<br>
<br>
-    auto abs_base = base.is_absolute() ? base : absolute(base);<br>
+  while (PP.State != PathParser::PS_BeforeBegin) {<br>
+    tmp.assign(createView(p.<wbr>native().data(), &PP.RawEntry.back()));<br>
+    std::error_code m_ec;<br>
+    file_status st = __status(tmp, &m_ec);<br>
+    if (!status_known(st)) {<br>
+      set_or_throw(m_ec, ec, "weakly_canonical", p);<br>
+      return {};<br>
+    } else if (exists(st)) {<br>
+      result = __canonical(tmp, ec);<br>
+      break;<br>
+    }<br>
+    DNEParts.push_back(*PP);<br>
+    --PP;<br>
+  }<br>
+  if (PP.State == PathParser::PS_BeforeBegin)<br>
+    result = __canonical("", ec);<br>
+  if (ec) ec->clear();<br>
+  if (DNEParts.empty())<br>
+    return result;<br>
+  for (auto It=DNEParts.rbegin(); It != DNEParts.rend(); ++It)<br>
+    result /= *It;<br>
+  return result.lexically_normal();<br>
+}<br>
+<br>
+<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
+//                            path definitions<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
+<br>
+constexpr path::value_type path::preferred_separator;<br>
+<br>
+path & path::replace_extension(path const & replacement)<br>
+{<br>
+    path p = extension();<br>
+    if (not p.empty()) {<br>
+      __pn_.erase(__pn_.size() - p.native().size());<br>
+    }<br>
+    if (!replacement.empty()) {<br>
+        if (replacement.native()[0] != '.') {<br>
+            __pn_ += ".";<br>
+        }<br>
+        __pn_.append(replacement.__pn_<wbr>);<br>
+    }<br>
+    return *this;<br>
+}<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
+// path.decompose<br>
+<br>
+string_view_t path::__root_name() const<br>
+{<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    if (PP.State == PathParser::PS_InRootName)<br>
+      return *PP;<br>
+    return {};<br>
+}<br>
<br>
-    /* !has_root_name && !has_root_dir */<br>
-    if (root_name.empty() && root_dir.empty())<br>
+string_view_t path::__root_directory() const<br>
+{<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    if (PP.State == PathParser::PS_InRootName)<br>
+      ++PP;<br>
+    if (PP.State == PathParser::PS_InRootDir)<br>
+      return *PP;<br>
+    return {};<br>
+}<br>
+<br>
+string_view_t path::__root_path_raw() const<br>
+{<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    if (PP.State == PathParser::PS_InRootName) {<br>
+      auto NextCh = PP.peek();<br>
+      if (NextCh && *NextCh == '/') {<br>
+        ++PP;<br>
+        return createView(__pn_.data(), &PP.RawEntry.back());<br>
+      }<br>
+      return PP.RawEntry;<br>
+    }<br>
+    if (PP.State == PathParser::PS_InRootDir)<br>
+      return *PP;<br>
+    return {};<br>
+}<br>
+<br>
+static bool ConsumeRootDir(PathParser* PP) {<br>
+  while (PP->State <= PathParser::PS_InRootDir)<br>
+    ++(*PP);<br>
+  return PP->State == PathParser::PS_AtEnd;<br>
+}<br>
+<br>
+string_view_t path::__relative_path() const<br>
+{<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    if (ConsumeRootDir(&PP))<br>
+      return {};<br>
+    return createView(PP.RawEntry.data(), &__pn_.back());<br>
+}<br>
+<br>
+string_view_t path::__parent_path() const<br>
+{<br>
+    if (empty())<br>
+      return {};<br>
+    // Determine if we have a root path but not a relative path. In that case<br>
+    // return *this.<br>
     {<br>
-      return abs_base / p;<br>
+      auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+      if (ConsumeRootDir(&PP))<br>
+        return __pn_;<br>
     }<br>
-    else if (!root_name.empty()) /* has_root_name && !has_root_dir */<br>
+    // Otherwise remove a single element from the end of the path, and return<br>
+    // a string representing that path<br>
     {<br>
-      return  root_name / abs_base.root_directory()<br>
-              /<br>
-              abs_base.relative_path() / p.relative_path();<br>
+      auto PP = PathParser::CreateEnd(__pn_);<br>
+      --PP;<br>
+      if (PP.RawEntry.data() == __pn_.data())<br>
+        return {};<br>
+      --PP;<br>
+      return createView(__pn_.data(), &PP.RawEntry.back());<br>
     }<br>
-    else /* !has_root_name && has_root_dir */<br>
+}<br>
+<br>
+string_view_t path::__filename() const<br>
+{<br>
+    if (empty()) return {};<br>
     {<br>
-      if (abs_base.has_root_name())<br>
-        return abs_base.root_name() / p;<br>
-      // else p is absolute,  return outside of block<br>
+      PathParser PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+      if (ConsumeRootDir(&PP))<br>
+        return {};<br>
     }<br>
-    return p;<br>
+    return *(--PathParser::CreateEnd(__<wbr>pn_));<br>
 }<br>
<br>
+string_view_t path::__stem() const<br>
+{<br>
+    return parser::separate_filename(__<wbr>filename()).first;<br>
+}<br>
+<br>
+string_view_t path::__extension() const<br>
+{<br>
+    return parser::separate_filename(__<wbr>filename()).second;<br>
+}<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
+// path.gen<br>
+<br>
+<br>
+enum PathPartKind : unsigned char {<br>
+  PK_None,<br>
+  PK_RootSep,<br>
+  PK_Filename,<br>
+  PK_Dot,<br>
+  PK_DotDot,<br>
+  PK_TrailingSep<br>
+};<br>
+<br>
+static PathPartKind ClassifyPathPart(string_view_t Part) {<br>
+  if (Part.empty())<br>
+    return PK_TrailingSep;<br>
+  if (Part == ".")<br>
+    return PK_Dot;<br>
+  if (Part == "..")<br>
+    return PK_DotDot;<br>
+  if (Part == "/")<br>
+    return PK_RootSep;<br>
+  return PK_Filename;<br>
+}<br>
+<br>
+path path::lexically_normal() const {<br>
+  if (__pn_.empty())<br>
+    return *this;<br>
+<br>
+  using PartKindPair = std::pair<string_view_t, PathPartKind>;<br>
+  std::vector<PartKindPair> Parts;<br>
+  // Guess as to how many elements the path has to avoid reallocating.<br>
+  Parts.reserve(32);<br>
+<br>
+  // Track the total size of the parts as we collect them. This allows the<br>
+  // resulting path to reserve the correct amount of memory.<br>
+  size_t NewPathSize = 0;<br>
+  auto AddPart = [&](PathPartKind K, string_view_t P) {<br>
+    NewPathSize += P.size();<br>
+    Parts.emplace_back(P, K);<br>
+  };<br>
+  auto LastPartKind = [&]() {<br>
+    if (Parts.empty())<br>
+      return PK_None;<br>
+    return Parts.back().second;<br>
+  };<br>
+<br>
+  bool MaybeNeedTrailingSep = false;<br>
+  // Build a stack containing the remaining elements of the path, popping off<br>
+  // elements which occur before a '..' entry.<br>
+  for (auto PP = PathParser::CreateBegin(__pn_)<wbr>; PP; ++PP) {<br>
+    auto Part = *PP;<br>
+    PathPartKind Kind = ClassifyPathPart(Part);<br>
+    switch (Kind) {<br>
+    case PK_Filename:<br>
+    case PK_RootSep: {<br>
+      // Add all non-dot and non-dot-dot elements to the stack of elements.<br>
+      AddPart(Kind, Part);<br>
+      MaybeNeedTrailingSep = false;<br>
+      break;<br>
+    }<br>
+    case PK_DotDot: {<br>
+      // Only push a ".." element if there are no elements preceding the "..",<br>
+      // or if the preceding element is itself "..".<br>
+      auto LastKind = LastPartKind();<br>
+      if (LastKind == PK_Filename) {<br>
+        NewPathSize -= Parts.back().first.size();<br>
+        Parts.pop_back();<br>
+      } else if (LastKind != PK_RootSep)<br>
+        AddPart(PK_DotDot, "..");<br>
+      MaybeNeedTrailingSep = LastKind == PK_Filename;<br>
+      break;<br>
+    }<br>
+    case PK_Dot:<br>
+    case PK_TrailingSep: {<br>
+      MaybeNeedTrailingSep = true;<br>
+      break;<br>
+    }<br>
+    case PK_None:<br>
+      _LIBCPP_UNREACHABLE();<br>
+    }<br>
+  }<br>
+  // [fs.path.generic]p6.8: If the path is empty, add a dot.<br>
+  if (Parts.empty())<br>
+     return ".";<br>
+<br>
+  // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any<br>
+  // trailing directory-separator.<br>
+  bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;<br>
+<br>
+  path Result;<br>
+  Result.__pn_.reserve(Parts.<wbr>size() + NewPathSize + NeedTrailingSep);<br>
+  for (auto &PK : Parts)<br>
+    Result /= PK.first;<br>
+<br>
+  if (NeedTrailingSep)<br>
+    Result /= "";<br>
+<br>
+  return Result;<br>
+}<br>
+<br>
+static int DetermineLexicalElementCount(<wbr>PathParser PP) {<br>
+  int Count = 0;<br>
+  for (; PP; ++PP) {<br>
+    auto Elem = *PP;<br>
+    if (Elem == "..")<br>
+      --Count;<br>
+    else if (Elem != ".")<br>
+      ++Count;<br>
+  }<br>
+  return Count;<br>
+}<br>
+<br>
+path path::lexically_relative(const path& base) const {<br>
+  { // perform root-name/root-directory mismatch checks<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    auto PPBase = PathParser::CreateBegin(base._<wbr>_pn_);<br>
+    auto CheckIterMismatchAtBase = [&]() {<br>
+        return PP.State != PPBase.State && (<br>
+            PP.inRootPath() || PPBase.inRootPath());<br>
+    };<br>
+    if (PP.State == PathParser::PS_InRootName &&<br>
+        PPBase.State == PathParser::PS_InRootName) {<br>
+      if (*PP != *PPBase)<br>
+        return {};<br>
+    } else if (CheckIterMismatchAtBase())<br>
+      return {};<br>
+<br>
+    if (PP.inRootPath()) ++PP;<br>
+    if (PPBase.inRootPath()) ++PPBase;<br>
+    if (CheckIterMismatchAtBase())<br>
+      return {};<br>
+  }<br>
+<br>
+  // Find the first mismatching element<br>
+  auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+  auto PPBase = PathParser::CreateBegin(base._<wbr>_pn_);<br>
+  while (PP && PPBase && PP.State == PPBase.State &&<br>
+         *PP == *PPBase) {<br>
+    ++PP;<br>
+    ++PPBase;<br>
+  }<br>
+<br>
+  // If there is no mismatch, return ".".<br>
+  if (!PP && !PPBase)<br>
+    return ".";<br>
+<br>
+  // Otherwise, determine the number of elements, 'n', which are not dot or<br>
+  // dot-dot minus the number of dot-dot elements.<br>
+  int ElemCount = DetermineLexicalElementCount(<wbr>PPBase);<br>
+  if (ElemCount < 0)<br>
+    return {};<br>
+<br>
+  // return a path constructed with 'n' dot-dot elements, followed by the the<br>
+  // elements of '*this' after the mismatch.<br>
+  path Result;<br>
+  // FIXME: Reserve enough room in Result that it won't have to re-allocate.<br>
+  while (ElemCount--)<br>
+    Result /= "..";<br>
+  for (; PP; ++PP)<br>
+    Result /= *PP;<br>
+  return Result;<br>
+}<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
+// path.comparisons<br>
+int path::__compare(string_view_t __s) const {<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    auto PP2 = PathParser::CreateBegin(__s);<br>
+    while (PP && PP2) {<br>
+        int res = (*PP).compare(*PP2);<br>
+        if (res != 0) return res;<br>
+        ++PP; ++PP2;<br>
+    }<br>
+    if (PP.State == PP2.State && !PP)<br>
+        return 0;<br>
+    if (!PP)<br>
+        return -1;<br>
+    return 1;<br>
+}<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
+// path.nonmembers<br>
+size_t hash_value(const path& __p) noexcept {<br>
+  auto PP = PathParser::CreateBegin(__p.<wbr>native());<br>
+  size_t hash_value = 0;<br>
+  std::hash<string_view_t> hasher;<br>
+  while (PP) {<br>
+    hash_value = __hash_combine(hash_value, hasher(*PP));<br>
+    ++PP;<br>
+  }<br>
+  return hash_value;<br>
+}<br>
+<br>
+/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
+// path.itr<br>
+path::iterator path::begin() const<br>
+{<br>
+    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
+    iterator it;<br>
+    it.__path_ptr_ = this;<br>
+    it.__state_ = PP.State;<br>
+    it.__entry_ = PP.RawEntry;<br>
+    it.__stashed_elem_.__assign_<wbr>view(*PP);<br>
+    return it;<br>
+}<br>
+<br>
+path::iterator path::end() const<br>
+{<br>
+    iterator it{};<br>
+    it.__state_ = PathParser::PS_AtEnd;<br>
+    it.__path_ptr_ = this;<br>
+    return it;<br>
+}<br>
+<br>
+path::iterator& path::iterator::__increment() {<br>
+  static_assert(__at_end == PathParser::PS_AtEnd, "");<br>
+  PathParser PP(__path_ptr_->native(), __entry_, __state_);<br>
+  ++PP;<br>
+  __state_ = PP.State;<br>
+  __entry_ = PP.RawEntry;<br>
+  __stashed_elem_.__assign_view(<wbr>*PP);<br>
+  return *this;<br>
+}<br>
+<br>
+path::iterator& path::iterator::__decrement() {<br>
+  PathParser PP(__path_ptr_->native(), __entry_, __state_);<br>
+  --PP;<br>
+  __state_ = PP.State;<br>
+  __entry_ = PP.RawEntry;<br>
+  __stashed_elem_.__assign_view(<wbr>*PP);<br>
+  return *this;<br>
+}<br>
+<br>
+<br>
 _LIBCPP_END_NAMESPACE_<wbr>EXPERIMENTAL_FILESYSTEM<br>
<br>
Removed: libcxx/trunk/src/experimental/<wbr>filesystem/path.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/path.cpp?rev=329027&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/src/<wbr>experimental/filesystem/path.<wbr>cpp?rev=329027&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/src/experimental/<wbr>filesystem/path.cpp (original)<br>
+++ libcxx/trunk/src/experimental/<wbr>filesystem/path.cpp (removed)<br>
@@ -1,448 +0,0 @@<br>
-//===--------------------- filesystem/path.cpp ----------------------------==<wbr>=//<br>
-//<br>
-//                     The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is dual licensed under the MIT and the University of Illinois Open<br>
-// Source Licenses. See LICENSE.TXT for details.<br>
-//<br>
-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
-#include "experimental/filesystem"<br>
-#include "string_view"<br>
-#include "utility"<br>
-<br>
-namespace { namespace parser<br>
-{<br>
-using namespace std;<br>
-using namespace std::experimental::filesystem;<br>
-<br>
-using string_view_t = path::__string_view;<br>
-using string_view_pair = pair<string_view_t, string_view_t>;<br>
-using PosPtr = path::value_type const*;<br>
-<br>
-struct PathParser {<br>
-  enum ParserState : unsigned char {<br>
-    // Zero is a special sentinel value used by default constructed iterators.<br>
-    PS_BeforeBegin = 1,<br>
-    PS_InRootName,<br>
-    PS_InRootDir,<br>
-    PS_InFilenames,<br>
-    PS_InTrailingSep,<br>
-    PS_AtEnd<br>
-  };<br>
-<br>
-  const string_view_t Path;<br>
-  string_view_t RawEntry;<br>
-  ParserState State;<br>
-<br>
-private:<br>
-  PathParser(string_view_t P, ParserState State) noexcept<br>
-      : Path(P), State(State) {}<br>
-<br>
-public:<br>
-  PathParser(string_view_t P, string_view_t E, unsigned char S)<br>
-      : Path(P), RawEntry(E), State(static_cast<ParserState><wbr>(S)) {<br>
-    // S cannot be '0' or PS_BeforeBegin.<br>
-  }<br>
-<br>
-  static PathParser CreateBegin(string_view_t P) noexcept {<br>
-    PathParser PP(P, PS_BeforeBegin);<br>
-    PP.increment();<br>
-    return PP;<br>
-  }<br>
-<br>
-  static PathParser CreateEnd(string_view_t P) noexcept {<br>
-    PathParser PP(P, PS_AtEnd);<br>
-    return PP;<br>
-  }<br>
-<br>
-  PosPtr peek() const noexcept {<br>
-    auto TkEnd = getNextTokenStartPos();<br>
-    auto End = getAfterBack();<br>
-    return TkEnd == End ? nullptr : TkEnd;<br>
-  }<br>
-<br>
-  void increment() noexcept {<br>
-    const PosPtr End = getAfterBack();<br>
-    const PosPtr Start = getNextTokenStartPos();<br>
-    if (Start == End)<br>
-      return makeState(PS_AtEnd);<br>
-<br>
-    switch (State) {<br>
-    case PS_BeforeBegin: {<br>
-      PosPtr TkEnd = consumeSeparator(Start, End);<br>
-      // If we consumed exactly two separators we have a root name.<br>
-      if (TkEnd && TkEnd == Start + 2) {<br>
-        // FIXME Do we need to consume a name or is '//' a root name on its own?<br>
-        // what about '//.', '//..', '//...'?<br>
-        auto NameEnd = consumeName(TkEnd, End);<br>
-        if (NameEnd)<br>
-          TkEnd = NameEnd;<br>
-        return makeState(PS_InRootName, Start, TkEnd);<br>
-      }<br>
-      else if (TkEnd)<br>
-        return makeState(PS_InRootDir, Start, TkEnd);<br>
-      else<br>
-        return makeState(PS_InFilenames, Start, consumeName(Start, End));<br>
-    }<br>
-<br>
-    case PS_InRootName:<br>
-      return makeState(PS_InRootDir, Start, consumeSeparator(Start, End));<br>
-    case PS_InRootDir:<br>
-      return makeState(PS_InFilenames, Start, consumeName(Start, End));<br>
-<br>
-    case PS_InFilenames: {<br>
-      PosPtr SepEnd = consumeSeparator(Start, End);<br>
-      if (SepEnd != End) {<br>
-        PosPtr TkEnd = consumeName(SepEnd, End);<br>
-        if (TkEnd)<br>
-          return makeState(PS_InFilenames, SepEnd, TkEnd);<br>
-      }<br>
-      return makeState(PS_InTrailingSep, Start, SepEnd);<br>
-    }<br>
-<br>
-    case PS_InTrailingSep:<br>
-      return makeState(PS_AtEnd);<br>
-<br>
-    case PS_AtEnd:<br>
-      _LIBCPP_UNREACHABLE();<br>
-    }<br>
-  }<br>
-<br>
-  void decrement() noexcept {<br>
-    const PosPtr REnd = getBeforeFront();<br>
-    const PosPtr RStart = getCurrentTokenStartPos() - 1;<br>
-<br>
-    switch (State) {<br>
-    case PS_AtEnd: {<br>
-      // Try to consume a trailing separator or root directory first.<br>
-      if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {<br>
-        if (SepEnd == REnd)<br>
-          return makeState((RStart == REnd + 2) ? PS_InRootName : PS_InRootDir,<br>
-                           Path.data(), RStart + 1);<br>
-        // Check if we're seeing the root directory separator<br>
-        auto PP = CreateBegin(Path);<br>
-        bool InRootDir = PP.State == PS_InRootName &&<br>
-            &PP.RawEntry.back() == SepEnd;<br>
-        return makeState(InRootDir ? PS_InRootDir : PS_InTrailingSep,<br>
-                         SepEnd + 1, RStart + 1);<br>
-      } else {<br>
-        PosPtr TkStart = consumeName(RStart, REnd);<br>
-        if (TkStart == REnd + 2 && consumeSeparator(TkStart, REnd) == REnd)<br>
-          return makeState(PS_InRootName, Path.data(), RStart + 1);<br>
-        else<br>
-          return makeState(PS_InFilenames, TkStart + 1, RStart + 1);<br>
-      }<br>
-    }<br>
-    case PS_InTrailingSep:<br>
-      return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, RStart + 1);<br>
-    case PS_InFilenames: {<br>
-      PosPtr SepEnd = consumeSeparator(RStart, REnd);<br>
-      if (SepEnd == REnd)<br>
-        return makeState((RStart == REnd + 2) ? PS_InRootName : PS_InRootDir,<br>
-                         Path.data(), RStart + 1);<br>
-      PosPtr TkEnd = consumeName(SepEnd, REnd);<br>
-      if (TkEnd == REnd + 2 && consumeSeparator(TkEnd, REnd) == REnd)<br>
-        return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);<br>
-      return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);<br>
-    }<br>
-    case PS_InRootDir:<br>
-      return makeState(PS_InRootName, Path.data(), RStart + 1);<br>
-    case PS_InRootName:<br>
-    case PS_BeforeBegin:<br>
-      _LIBCPP_UNREACHABLE();<br>
-    }<br>
-  }<br>
-<br>
-  /// \brief Return a view with the "preferred representation" of the current<br>
-  ///   element. For example trailing separators are represented as a '.'<br>
-  string_view_t operator*() const noexcept {<br>
-    switch (State) {<br>
-    case PS_BeforeBegin:<br>
-    case PS_AtEnd:<br>
-      return "";<br>
-    case PS_InRootDir:<br>
-      return "/";<br>
-    case PS_InTrailingSep:<br>
-      return ".";<br>
-    case PS_InRootName:<br>
-    case PS_InFilenames:<br>
-      return RawEntry;<br>
-    }<br>
-    _LIBCPP_UNREACHABLE();<br>
-  }<br>
-<br>
-  explicit operator bool() const noexcept {<br>
-    return State != PS_BeforeBegin && State != PS_AtEnd;<br>
-  }<br>
-<br>
-  PathParser& operator++() noexcept {<br>
-    increment();<br>
-    return *this;<br>
-  }<br>
-<br>
-  PathParser& operator--() noexcept {<br>
-    decrement();<br>
-    return *this;<br>
-  }<br>
-<br>
-private:<br>
-  void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {<br>
-    State = NewState;<br>
-    RawEntry = string_view_t(Start, End - Start);<br>
-  }<br>
-  void makeState(ParserState NewState) noexcept {<br>
-    State = NewState;<br>
-    RawEntry = {};<br>
-  }<br>
-<br>
-  PosPtr getAfterBack() const noexcept {<br>
-    return Path.data() + Path.size();<br>
-  }<br>
-<br>
-  PosPtr getBeforeFront() const noexcept {<br>
-    return Path.data() - 1;<br>
-  }<br>
-<br>
-  /// \brief Return a pointer to the first character after the currently<br>
-  ///   lexed element.<br>
-  PosPtr getNextTokenStartPos() const noexcept {<br>
-    switch (State) {<br>
-    case PS_BeforeBegin:<br>
-      return Path.data();<br>
-    case PS_InRootName:<br>
-    case PS_InRootDir:<br>
-    case PS_InFilenames:<br>
-      return &RawEntry.back() + 1;<br>
-    case PS_InTrailingSep:<br>
-    case PS_AtEnd:<br>
-      return getAfterBack();<br>
-    }<br>
-    _LIBCPP_UNREACHABLE();<br>
-  }<br>
-<br>
-  /// \brief Return a pointer to the first character in the currently lexed<br>
-  ///   element.<br>
-  PosPtr getCurrentTokenStartPos() const noexcept {<br>
-    switch (State) {<br>
-    case PS_BeforeBegin:<br>
-    case PS_InRootName:<br>
-      return &Path.front();<br>
-    case PS_InRootDir:<br>
-    case PS_InFilenames:<br>
-    case PS_InTrailingSep:<br>
-      return &RawEntry.front();<br>
-    case PS_AtEnd:<br>
-      return &Path.back() + 1;<br>
-    }<br>
-    _LIBCPP_UNREACHABLE();<br>
-  }<br>
-<br>
-  PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {<br>
-    if (P == End || *P != '/')<br>
-      return nullptr;<br>
-    const int Inc = P < End ? 1 : -1;<br>
-    P += Inc;<br>
-    while (P != End && *P == '/')<br>
-      P += Inc;<br>
-    return P;<br>
-  }<br>
-<br>
-  PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {<br>
-    if (P == End || *P == '/')<br>
-      return nullptr;<br>
-    const int Inc = P < End ? 1 : -1;<br>
-    P += Inc;<br>
-    while (P != End && *P != '/')<br>
-      P += Inc;<br>
-    return P;<br>
-  }<br>
-};<br>
-<br>
-string_view_pair separate_filename(string_view_<wbr>t const & s) {<br>
-    if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};<br>
-    auto pos = s.find_last_of('.');<br>
-    if (pos == string_view_t::npos)<br>
-        return string_view_pair{s, string_view_t{}};<br>
-    return string_view_pair{s.substr(0, pos), s.substr(pos)};<br>
-}<br>
-<br>
-string_view_t createView(PosPtr S, PosPtr E) noexcept {<br>
-  return {S, static_cast<size_t>(E - S) + 1};<br>
-}<br>
-<br>
-}} // namespace parser<br>
-<br>
-_LIBCPP_BEGIN_NAMESPACE_<wbr>EXPERIMENTAL_FILESYSTEM<br>
-<br>
-using parser::string_view_t;<br>
-using parser::string_view_pair;<br>
-using parser::PathParser;<br>
-using parser::createView;<br>
-<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
-//                            path definitions<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
-<br>
-constexpr path::value_type path::preferred_separator;<br>
-<br>
-path & path::replace_extension(path const & replacement)<br>
-{<br>
-    path p = extension();<br>
-    if (not p.empty()) {<br>
-      __pn_.erase(__pn_.size() - p.native().size());<br>
-    }<br>
-    if (!replacement.empty()) {<br>
-        if (replacement.native()[0] != '.') {<br>
-            __pn_ += ".";<br>
-        }<br>
-        __pn_.append(replacement.__pn_<wbr>);<br>
-    }<br>
-    return *this;<br>
-}<br>
-<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>////////////////////<br>
-// path.decompose<br>
-<br>
-string_view_t path::__root_name() const<br>
-{<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    if (PP.State == PathParser::PS_InRootName)<br>
-      return *PP;<br>
-    return {};<br>
-}<br>
-<br>
-string_view_t path::__root_directory() const<br>
-{<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    if (PP.State == PathParser::PS_InRootName)<br>
-      ++PP;<br>
-    if (PP.State == PathParser::PS_InRootDir)<br>
-      return *PP;<br>
-    return {};<br>
-}<br>
-<br>
-string_view_t path::__root_path_raw() const<br>
-{<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    if (PP.State == PathParser::PS_InRootName) {<br>
-      auto NextCh = PP.peek();<br>
-      if (NextCh && *NextCh == '/') {<br>
-        ++PP;<br>
-        return createView(__pn_.data(), &PP.RawEntry.back());<br>
-      }<br>
-      return PP.RawEntry;<br>
-    }<br>
-    if (PP.State == PathParser::PS_InRootDir)<br>
-      return *PP;<br>
-    return {};<br>
-}<br>
-<br>
-string_view_t path::__relative_path() const<br>
-{<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    while (PP.State <= PathParser::PS_InRootDir)<br>
-      ++PP;<br>
-    if (PP.State == PathParser::PS_AtEnd)<br>
-      return {};<br>
-    return createView(PP.RawEntry.data(), &__pn_.back());<br>
-}<br>
-<br>
-string_view_t path::__parent_path() const<br>
-{<br>
-    if (empty())<br>
-      return {};<br>
-    auto PP = PathParser::CreateEnd(__pn_);<br>
-    --PP;<br>
-    if (PP.RawEntry.data() == __pn_.data())<br>
-      return {};<br>
-    --PP;<br>
-    return createView(__pn_.data(), &PP.RawEntry.back());<br>
-}<br>
-<br>
-string_view_t path::__filename() const<br>
-{<br>
-    if (empty()) return {};<br>
-    return *(--PathParser::CreateEnd(__<wbr>pn_));<br>
-}<br>
-<br>
-string_view_t path::__stem() const<br>
-{<br>
-    return parser::separate_filename(__<wbr>filename()).first;<br>
-}<br>
-<br>
-string_view_t path::__extension() const<br>
-{<br>
-    return parser::separate_filename(__<wbr>filename()).second;<br>
-}<br>
-<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
-// path.comparisons<br>
-int path::__compare(string_view_t __s) const {<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    auto PP2 = PathParser::CreateBegin(__s);<br>
-    while (PP && PP2) {<br>
-        int res = (*PP).compare(*PP2);<br>
-        if (res != 0) return res;<br>
-        ++PP; ++PP2;<br>
-    }<br>
-    if (PP.State == PP2.State && PP.State == PathParser::PS_AtEnd)<br>
-        return 0;<br>
-    if (PP.State == PathParser::PS_AtEnd)<br>
-        return -1;<br>
-    return 1;<br>
-}<br>
-<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
-// path.nonmembers<br>
-size_t hash_value(const path& __p) noexcept {<br>
-  auto PP = PathParser::CreateBegin(__p.<wbr>native());<br>
-  size_t hash_value = 0;<br>
-  std::hash<string_view_t> hasher;<br>
-  while (PP) {<br>
-    hash_value = __hash_combine(hash_value, hasher(*PP));<br>
-    ++PP;<br>
-  }<br>
-  return hash_value;<br>
-}<br>
-<br>
-/////////////////////////////<wbr>//////////////////////////////<wbr>/////////////////<br>
-// path.itr<br>
-path::iterator path::begin() const<br>
-{<br>
-    auto PP = PathParser::CreateBegin(__pn_)<wbr>;<br>
-    iterator it;<br>
-    it.__path_ptr_ = this;<br>
-    it.__state_ = PP.State;<br>
-    it.__entry_ = PP.RawEntry;<br>
-    it.__stashed_elem_.__assign_<wbr>view(*PP);<br>
-    return it;<br>
-}<br>
-<br>
-path::iterator path::end() const<br>
-{<br>
-    iterator it{};<br>
-    it.__state_ = PathParser::PS_AtEnd;<br>
-    it.__path_ptr_ = this;<br>
-    return it;<br>
-}<br>
-<br>
-path::iterator& path::iterator::__increment() {<br>
-  static_assert(__at_end == PathParser::PS_AtEnd, "");<br>
-  PathParser PP(__path_ptr_->native(), __entry_, __state_);<br>
-  ++PP;<br>
-  __state_ = PP.State;<br>
-  __entry_ = PP.RawEntry;<br>
-  __stashed_elem_.__assign_view(<wbr>*PP);<br>
-  return *this;<br>
-}<br>
-<br>
-path::iterator& path::iterator::__decrement() {<br>
-  PathParser PP(__path_ptr_->native(), __entry_, __state_);<br>
-  --PP;<br>
-  __state_ = PP.State;<br>
-  __entry_ = PP.RawEntry;<br>
-  __stashed_elem_.__assign_view(<wbr>*PP);<br>
-  return *this;<br>
-}<br>
-<br>
-_LIBCPP_END_NAMESPACE_<wbr>EXPERIMENTAL_FILESYSTEM<br>
<br>
Removed: libcxx/trunk/test/libcxx/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/experimental/filesystem/class.path/path.member/path.append.pass.cpp?rev=329027&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/<wbr>libcxx/experimental/<wbr>filesystem/class.path/path.<wbr>member/path.append.pass.cpp?<wbr>rev=329027&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/libcxx/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/libcxx/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp (removed)<br>
@@ -1,70 +0,0 @@<br>
-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
-//<br>
-//                     The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is dual licensed under the MIT and the University of Illinois Open<br>
-// Source Licenses. See LICENSE.TXT for details.<br>
-//<br>
-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
-<br>
-// UNSUPPORTED: c++98, c++03<br>
-<br>
-// <experimental/filesystem><br>
-<br>
-// class path<br>
-<br>
-// path& operator/=(path const&)<br>
-// path operator/(path const&, path const&)<br>
-<br>
-<br>
-#define _LIBCPP_DEBUG 0<br>
-#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)<br>
-int AssertCount = 0;<br>
-<br>
-#include <experimental/filesystem><br>
-#include <type_traits><br>
-#include <string_view><br>
-#include <cassert><br>
-<br>
-#include "test_macros.h"<br>
-#include "test_iterators.h"<br>
-#include "count_new.hpp"<br>
-#include "filesystem_test_helper.hpp"<br>
-<br>
-namespace fs = std::experimental::filesystem;<br>
-<br>
-int main()<br>
-{<br>
-  using namespace fs;<br>
-  {<br>
-    path lhs("//foo");<br>
-    path rhs("/bar");<br>
-    assert(AssertCount == 0);<br>
-    lhs /= rhs;<br>
-    assert(AssertCount == 0);<br>
-  }<br>
-  {<br>
-    path lhs("//foo");<br>
-    path rhs("/bar");<br>
-    assert(AssertCount == 0);<br>
-    (void)(lhs / rhs);<br>
-    assert(AssertCount == 0);<br>
-  }<br>
-  {<br>
-    path lhs("//foo");<br>
-    path rhs("//bar");<br>
-    assert(AssertCount == 0);<br>
-    lhs /= rhs;<br>
-    assert(AssertCount == 1);<br>
-    AssertCount = 0;<br>
-  }<br>
-  {<br>
-    path lhs("//foo");<br>
-    path rhs("//bar");<br>
-    assert(AssertCount == 0);<br>
-    (void)(lhs / rhs);<br>
-    assert(AssertCount == 1);<br>
-  }<br>
-  // FIXME The same error is not diagnosed for the append(Source) and<br>
-  // append(It, It) overloads.<br>
-}<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.itr/iterator.pass.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.itr/iterator.pass.<wbr>cpp?rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.itr/iterator.pass.<wbr>cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.itr/iterator.pass.<wbr>cpp Mon Apr  2 16:03:41 2018<br>
@@ -83,14 +83,14 @@ void checkBeginEndBasic() {<br>
   }<br>
   {<br>
     path p("//root_name//first_dir////<wbr>second_dir");<br>
-    const path expect[] = {"//root_name", "/", "first_dir", "second_dir"};<br>
+    const path expect[] = {"/", "root_name", "first_dir", "second_dir"};<br>
     assert(checkCollectionsEqual(<wbr>p.begin(), p.end(), std::begin(expect), std::end(expect)));<br>
     assert(<wbr>checkCollectionsEqualBackwards<wbr>(p.begin(), p.end(), std::begin(expect), std::end(expect)));<br>
<br>
   }<br>
   {<br>
     path p("////foo/bar/baz///");<br>
-    const path expect[] = {"/", "foo", "bar", "baz", "."};<br>
+    const path expect[] = {"/", "foo", "bar", "baz", ""};<br>
     assert(checkCollectionsEqual(<wbr>p.begin(), p.end(), std::begin(expect), std::end(expect)));<br>
     assert(<wbr>checkCollectionsEqualBackwards<wbr>(p.begin(), p.end(), std::begin(expect), std::end(expect)));<br>
<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp?rev=329028&r1=329027&<wbr>r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.append.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -31,6 +31,7 @@<br>
 #include "test_iterators.h"<br>
 #include "count_new.hpp"<br>
 #include "filesystem_test_helper.hpp"<br>
+#include "verbose_assert.h"<br>
<br>
<br>
 struct AppendOperatorTestcase {<br>
@@ -45,13 +46,22 @@ const AppendOperatorTestcase Cases[] =<br>
         {S(""),     S(""),      S("")}<br>
       , {S("p1"),   S("p2"),    S("p1/p2")}<br>
       , {S("p1/"),  S("p2"),    S("p1/p2")}<br>
-      , {S("p1"),   S("/p2"),   S("p1/p2")}<br>
-      , {S("p1/"),  S("/p2"),   S("p1//p2")}<br>
+      , {S("p1"),   S("/p2"),   S("/p2")}<br>
+      , {S("p1/"),  S("/p2"),   S("/p2")}<br>
       , {S("p1"),   S("\\p2"),  S("p1/\\p2")}<br>
       , {S("p1\\"), S("p2"),  S("p1\\/p2")}<br>
       , {S("p1\\"), S("\\p2"),  S("p1\\/\\p2")}<br>
-      , {S("p1"),   S(""),      S("p1")}<br>
       , {S(""),     S("p2"),    S("p2")}<br>
+      , {S("/p1"),  S("p2"),    S("/p1/p2")}<br>
+      , {S("/p1"),  S("/p2"),    S("/p2")}<br>
+      , {S("/p1/p3"),  S("p2"),    S("/p1/p3/p2")}<br>
+      , {S("/p1/p3/"),  S("p2"),    S("/p1/p3/p2")}<br>
+      , {S("/p1/"),  S("p2"),    S("/p1/p2")}<br>
+      , {S("/p1/p3/"),  S("/p2/p4"),    S("/p2/p4")}<br>
+      , {S("/"),    S(""),      S("/")}<br>
+      , {S("/p1"), S("/p2/"), S("/p2/")}<br>
+      , {S("p1"),   S(""),      S("p1/")}<br>
+      , {S("p1/"),  S(""),      S("p1/")}<br>
     };<br>
<br>
<br>
@@ -59,7 +69,8 @@ const AppendOperatorTestcase LongLHSCase<br>
     {<br>
         {S("p1"),   S("p2"),    S("p1/p2")}<br>
       , {S("p1/"),  S("p2"),    S("p1/p2")}<br>
-      , {S("p1"),   S("/p2"),   S("p1/p2")}<br>
+      , {S("p1"),   S("/p2"),   S("/p2")}<br>
+      , {S("/p1"),  S("p2"),    S("/p1/p2")}<br>
     };<br>
 #undef S<br>
<br>
@@ -98,7 +109,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       DisableAllocationGuard g;<br>
       LHS /= RHS;<br>
     }<br>
-    assert(LHS == E);<br>
+    ASSERT_PRED(PathEq, LHS , E);<br>
   }<br>
   // basic_string_view<br>
   {<br>
@@ -108,7 +119,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       DisableAllocationGuard g;<br>
       LHS /= RHS;<br>
     }<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
   }<br>
   // CharT*<br>
   {<br>
@@ -118,7 +129,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       DisableAllocationGuard g;<br>
       LHS /= RHS;<br>
     }<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
   }<br>
   {<br>
     path LHS(L); PathReserve(LHS, ReserveSize);<br>
@@ -127,7 +138,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       DisableAllocationGuard g;<br>
       LHS.append(RHS, StrEnd(RHS));<br>
     }<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
   }<br>
   // input iterator - For non-native char types, appends needs to copy the<br>
   // iterator range into a contiguous block of memory before it can perform the<br>
@@ -143,7 +154,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       if (DisableAllocations) g.requireExactly(0);<br>
       LHS /= RHS;<br>
     }<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
   }<br>
   {<br>
     path LHS(L); PathReserve(LHS, ReserveSize);<br>
@@ -154,7 +165,7 @@ void doAppendSourceAllocTest(<wbr>AppendOpera<br>
       if (DisableAllocations) g.requireExactly(0);<br>
       LHS.append(RHS, REnd);<br>
     }<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
   }<br>
 }<br>
<br>
@@ -171,17 +182,18 @@ void doAppendSourceTest(<wbr>AppendOperatorTe<br>
   const Ptr E = TC.expect;<br>
   // basic_string<br>
   {<br>
-    path LHS(L);<br>
+    path Result(L);<br>
     Str RHS(R);<br>
-    path& Ref = (LHS /= RHS);<br>
-    assert(LHS == E);<br>
-    assert(&Ref == &LHS);<br>
+    path& Ref = (Result /= RHS);<br>
+    ASSERT_EQ(Result, E)<br>
+        << DISPLAY(L) << DISPLAY(R);<br>
+    assert(&Ref == &Result);<br>
   }<br>
   {<br>
     path LHS(L);<br>
     Str RHS(R);<br>
     path& Ref = LHS.append(RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   // basic_string_view<br>
@@ -189,14 +201,14 @@ void doAppendSourceTest(<wbr>AppendOperatorTe<br>
     path LHS(L);<br>
     StrView RHS(R);<br>
     path& Ref = (LHS /= RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   {<br>
     path LHS(L);<br>
     StrView RHS(R);<br>
     path& Ref = LHS.append(RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   // Char*<br>
@@ -204,21 +216,22 @@ void doAppendSourceTest(<wbr>AppendOperatorTe<br>
     path LHS(L);<br>
     Str RHS(R);<br>
     path& Ref = (LHS /= RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   {<br>
     path LHS(L);<br>
     Ptr RHS(R);<br>
     path& Ref = LHS.append(RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   {<br>
     path LHS(L);<br>
     Ptr RHS(R);<br>
     path& Ref = LHS.append(RHS, StrEnd(RHS));<br>
-    assert(LHS == E);<br>
+    ASSERT_PRED(PathEq, LHS, E)<br>
+        << DISPLAY(L) << DISPLAY(R);<br>
     assert(&Ref == &LHS);<br>
   }<br>
   // iterators<br>
@@ -226,13 +239,13 @@ void doAppendSourceTest(<wbr>AppendOperatorTe<br>
     path LHS(L);<br>
     InputIter RHS(R);<br>
     path& Ref = (LHS /= RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   {<br>
     path LHS(L); InputIter RHS(R);<br>
     path& Ref = LHS.append(RHS);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
   {<br>
@@ -240,7 +253,7 @@ void doAppendSourceTest(<wbr>AppendOperatorTe<br>
     InputIter RHS(R);<br>
     InputIter REnd(StrEnd(R));<br>
     path& Ref = LHS.append(RHS, REnd);<br>
-    assert(LHS == E);<br>
+    assert(PathEq(LHS, E));<br>
     assert(&Ref == &LHS);<br>
   }<br>
 }<br>
@@ -304,11 +317,14 @@ int main()<br>
   using namespace fs;<br>
   for (auto const & TC : Cases) {<br>
     {<br>
-      path LHS((const char*)TC.lhs);<br>
-      path RHS((const char*)TC.rhs);<br>
-      path& Ref = (LHS /= RHS);<br>
-      assert(LHS == (const char*)TC.expect);<br>
-      assert(&Ref == &LHS);<br>
+      const char* LHS_In = TC.lhs;<br>
+      const char* RHS_In = TC.rhs;<br>
+      path LHS(LHS_In);<br>
+      path RHS(RHS_In);<br>
+      path& Res = (LHS /= RHS);<br>
+      ASSERT_PRED(PathEq, Res, (const char*)TC.expect)<br>
+          << DISPLAY(LHS_In) << DISPLAY(RHS_In);<br>
+      assert(&Res == &LHS);<br>
     }<br>
     doAppendSourceTest<char>    (TC);<br>
     doAppendSourceTest<wchar_t> (TC);<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.compare.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.compare.<wbr>pass.cpp?rev=329028&r1=329027&<wbr>r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.compare.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.compare.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -26,6 +26,7 @@<br>
 //<br>
 // size_t hash_value(path const&) noexcept;<br>
<br>
+<br>
 #include "filesystem_include.hpp"<br>
 #include <type_traits><br>
 #include <vector><br>
@@ -35,7 +36,7 @@<br>
 #include "test_iterators.h"<br>
 #include "count_new.hpp"<br>
 #include "filesystem_test_helper.hpp"<br>
-<br>
+#include "verbose_assert.h"<br>
<br>
 struct PathCompareTest {<br>
   const char* LHS;<br>
@@ -57,8 +58,9 @@ const PathCompareTest CompareTestCases[]<br>
     {"a/b/c", "b/a/c", -1},<br>
     {"a/b", "a/b/c", -1},<br>
     {"a/b/c", "a/b", 1},<br>
-    {"a/b/", "a/b/.", 0},<br>
-    {"a/b//////", "a/b/////.", 0},<br>
+    {"a/b/", "a/b/.", -1},<br>
+    {"a/b/", "a/b",    1},<br>
+    {"a/b//////", "a/b/////.", -1},<br>
     {"a/.././b", "a///..//.////b", 0},<br>
     {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators<br>
     {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory<br>
@@ -94,8 +96,13 @@ int main()<br>
       int ret2 = normalize_ret(p1.compare(R));<br>
       int ret3 = normalize_ret(p1.compare(TC.<wbr>RHS));<br>
       int ret4 = normalize_ret(p1.compare(RV));<br>
-      assert(ret1 == ret2 && ret1 == ret3 && ret1 == ret4);<br>
-      assert(ret1 == E);<br>
+<br>
+      g.release();<br>
+      ASSERT_EQ(ret1, ret2);<br>
+      ASSERT_EQ(ret1, ret3);<br>
+      ASSERT_EQ(ret1, ret4);<br>
+      ASSERT_EQ(ret1, E)<br>
+          << DISPLAY(TC.LHS) << DISPLAY(TC.RHS);<br>
<br>
       // check signatures<br>
       ASSERT_NOEXCEPT(p1.compare(p2)<wbr>);<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/empty.fail.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.decompose/empty.fail.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/empty.fail.cpp?rev=<wbr>329028&r1=329027&r2=329028&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/empty.fail.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/empty.fail.cpp Mon Apr  2 16:03:41 2018<br>
@@ -18,6 +18,7 @@<br>
 // UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8<br>
<br>
 #include "filesystem_include.hpp"<br>
+<br>
 #include "test_macros.h"<br>
<br>
 int main ()<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/path.decompose.pass.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/path.decompose.pass.<wbr>cpp?rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/path.decompose.pass.<wbr>cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>decompose/path.decompose.pass.<wbr>cpp Mon Apr  2 16:03:41 2018<br>
@@ -53,6 +53,14 @@<br>
 #include "test_iterators.h"<br>
 #include "count_new.hpp"<br>
 #include "filesystem_test_helper.hpp"<br>
+#include "assert_checkpoint.h"<br>
+#include "verbose_assert.h"<br>
+<br>
+struct ComparePathExact {<br>
+  bool operator()(std::string const& LHS, std::string const& RHS) const {<br>
+    return LHS == RHS;<br>
+  }<br>
+};<br>
<br>
 struct PathDecomposeTestcase<br>
 {<br>
@@ -72,80 +80,89 @@ const PathDecomposeTestcase PathTestCase<br>
     , {".", {"."}, "", "", "", ".", "", "."}<br>
     , {"..", {".."}, "", "", "", "..", "", ".."}<br>
     , {"foo", {"foo"}, "", "", "", "foo", "", "foo"}<br>
-    , {"/", {"/"}, "/", "", "/", "", "", "/"}<br>
+    , {"/", {"/"}, "/", "", "/", "", "/", ""}<br>
     , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"}<br>
-    , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."}<br>
-    , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."}<br>
+    , {"foo/", {"foo", ""}, "", "", "", "foo/", "foo", ""}<br>
+    , {"/foo/", {"/", "foo", ""}, "/", "", "/", "foo/", "/foo", ""}<br>
     , {"foo/bar", {"foo","bar"}, "",  "", "",  "foo/bar", "foo", "bar"}<br>
     , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"}<br>
-    , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"}<br>
-    , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/", "foo", "//net/", "foo"}<br>
-    , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///", "///foo", "."}<br>
+    , {"//net", {"/", "net"}, "/", "", "/", "net", "/", "net"}<br>
+    , {"//net/foo", {"/", "net", "foo"}, "/", "", "/", "net/foo", "/net", "foo"}<br>
+    , {"///foo///", {"/", "foo", ""}, "/", "", "/", "foo///", "///foo", ""}<br>
     , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"}<br>
     , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."}<br>
-    , {"./", {".", "."}, "", "", "", "./", ".", "."}<br>
+    , {"./", {".", ""}, "", "", "", "./", ".", ""}<br>
     , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."}<br>
-    , {"../", {"..", "."}, "", "", "", "../", "..", "."}<br>
+    , {"../", {"..", ""}, "", "", "", "../", "..", ""}<br>
     , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."}<br>
     , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."}<br>
-    , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."}<br>
+    , {"foo/./", {"foo", ".", ""}, "", "", "", "foo/./", "foo/.", ""}<br>
     , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"}<br>
-    , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..", "."}<br>
+    , {"foo/../", {"foo", "..", ""}, "", "", "", "foo/../", "foo/..", ""}<br>
     , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"}<br>
     , {"c:", {"c:"}, "", "", "", "c:", "", "c:"}<br>
-    , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."}<br>
+    , {"c:/", {"c:", ""}, "", "", "", "c:/", "c:", ""}<br>
     , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"}<br>
     , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"}<br>
-    , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."}<br>
-    , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/",  "c:/foo", "."}<br>
+    , {"c:foo/", {"c:foo", ""}, "", "", "", "c:foo/", "c:foo", ""}<br>
+    , {"c:/foo/", {"c:", "foo", ""}, "", "", "", "c:/foo/",  "c:/foo", ""}<br>
     , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"}<br>
     , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"}<br>
     , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"}<br>
     , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"}<br>
     , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"}<br>
     , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"}<br>
-    , {"c:\\foo/",  {"c:\\foo", "."}, "", "", "", "c:\\foo/", "c:\\foo", "."}<br>
+    , {"c:\\foo/",  {"c:\\foo", ""}, "", "", "", "c:\\foo/", "c:\\foo", ""}<br>
     , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"}<br>
-    , {"//", {"//"}, "//", "//", "", "", "", "//"}<br>
+    , {"//", {"/"}, "/", "", "/", "", "/", ""}<br>
   };<br>
<br>
 void decompPathTest()<br>
 {<br>
   using namespace fs;<br>
   for (auto const & TC : PathTestCases) {<br>
-    path p(TC.raw);<br>
-    assert(p == TC.raw);<br>
-<br>
-    assert(p.root_path() == TC.root_path);<br>
-    assert(p.has_root_path() !=  TC.root_path.empty());<br>
-<br>
-    assert(p.root_name() == TC.root_name);<br>
-    assert(p.has_root_name() !=  TC.root_name.empty());<br>
-<br>
-    assert(p.root_directory() == TC.root_directory);<br>
-    assert(p.has_root_directory() !=  TC.root_directory.empty());<br>
-<br>
-    assert(p.relative_path() == TC.relative_path);<br>
-    assert(p.has_relative_path() !=  TC.relative_path.empty());<br>
-<br>
-    assert(p.parent_path() == TC.parent_path);<br>
-    assert(p.has_parent_path() !=  TC.parent_path.empty());<br>
-<br>
-    assert(p.filename() == TC.filename);<br>
-    assert(p.has_filename() !=  TC.filename.empty());<br>
-<br>
-    assert(p.is_absolute() == p.has_root_directory());<br>
-    assert(p.is_relative() !=  p.is_absolute());<br>
-<br>
-    assert(checkCollectionsEqual(<wbr>p.begin(), p.end(),<br>
-                                 TC.elements.begin(), TC.elements.end()));<br>
+    CHECKPOINT(TC.raw.c_str());<br>
+    fs::path p(TC.raw);<br>
+    ASSERT(p == TC.raw);<br>
+<br>
+    ASSERT_EQ(p.root_path(), TC.root_path);<br>
+    ASSERT_NEQ(p.has_root_path(), TC.root_path.empty());<br>
+<br>
+    ASSERT(p.root_name().native().<wbr>empty())<br>
+        << DISPLAY(p.root_name());<br>
+    ASSERT_EQ(p.root_name(),TC.<wbr>root_name);<br>
+    ASSERT_NEQ(p.has_root_name(), TC.root_name.empty());<br>
+<br>
+    ASSERT_EQ(p.root_directory(), TC.root_directory);<br>
+    ASSERT_NEQ(p.has_root_<wbr>directory(), TC.root_directory.empty());<br>
+<br>
+    ASSERT_EQ(p.relative_path(), TC.relative_path);<br>
+    ASSERT_NEQ(p.has_relative_<wbr>path(), TC.relative_path.empty());<br>
+<br>
+    ASSERT_EQ(p.parent_path(), TC.parent_path);<br>
+    ASSERT_NEQ(p.has_parent_path()<wbr>, TC.parent_path.empty());<br>
+<br>
+    ASSERT_EQ(p.filename(), TC.filename);<br>
+    ASSERT_NEQ(p.has_filename(), TC.filename.empty());<br>
+<br>
+    ASSERT_EQ(p.is_absolute(), p.has_root_directory());<br>
+    ASSERT_NEQ(p.is_relative(), p.is_absolute());<br>
+    if (p.empty())<br>
+      ASSERT(p.is_relative());<br>
+<br>
+    ASSERT_COLLECTION_EQ_COMP(<br>
+        p.begin(), p.end(),<br>
+        TC.elements.begin(), TC.elements.end(),<br>
+        ComparePathExact()<br>
+    );<br>
     // check backwards<br>
<br>
     std::vector<fs::path> Parts;<br>
     for (auto it = p.end(); it != p.begin(); )<br>
       Parts.push_back(*--it);<br>
-    assert(checkCollectionsEqual(<wbr>Parts.begin(), Parts.end(),<br>
-                                 TC.elements.rbegin(), TC.elements.rend()));<br>
+    ASSERT_COLLECTION_EQ_COMP(<wbr>Parts.begin(), Parts.end(),<br>
+                                 TC.elements.rbegin(), TC.elements.rend(),<br>
+                              ComparePathExact());<br>
   }<br>
 }<br>
<br>
@@ -163,10 +180,12 @@ const FilenameDecompTestcase FilenameTes<br>
     {"", "", "", ""}<br>
   , {".", ".", ".", ""}<br>
   , {"..", "..", "..", ""}<br>
-  , {"/", "/", "/", ""}<br>
+  , {"/", "", "", ""}<br>
   , {"foo", "foo", "foo", ""}<br>
   , {"/foo/bar.txt", "bar.txt", "bar", ".txt"}<br>
   , {"foo..txt", "foo..txt", "foo.", ".txt"}<br>
+  , {".profile", ".profile", ".profile", ""}<br>
+  , {".profile.txt", ".profile.txt", ".profile", ".txt"}<br>
 };<br>
<br>
<br>
@@ -174,18 +193,19 @@ void decompFilenameTest()<br>
 {<br>
   using namespace fs;<br>
   for (auto const & TC : FilenameTestCases) {<br>
-    path p(TC.raw);<br>
-    assert(p == TC.raw);<br>
+    CHECKPOINT(TC.raw.c_str());<br>
+    fs::path p(TC.raw);<br>
+    ASSERT_EQ(p, TC.raw);<br>
     ASSERT_NOEXCEPT(p.empty());<br>
<br>
-    assert(p.filename() == TC.filename);<br>
-    assert(p.has_filename() != TC.filename.empty());<br>
+    ASSERT_EQ(p.filename(), TC.filename);<br>
+    ASSERT_NEQ(p.has_filename(), TC.filename.empty());<br>
<br>
-    assert(p.stem() == TC.stem);<br>
-    assert(p.has_stem() != TC.stem.empty());<br>
+    ASSERT_EQ(p.stem(), TC.stem);<br>
+    ASSERT_NEQ(p.has_stem(), TC.stem.empty());<br>
<br>
-    assert(p.extension() == TC.extension);<br>
-    assert(p.has_extension() != TC.extension.empty());<br>
+    ASSERT_EQ(p.extension(), TC.extension);<br>
+    ASSERT_NEQ(p.has_extension(), TC.extension.empty());<br>
   }<br>
 }<br>
<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_normal.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_normal.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_normal.pass.cpp?rev=<wbr>329028&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_normal.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_normal.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,142 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// class path<br>
+<br>
+// path lexically_normal() const;<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <vector><br>
+#include <iostream><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "test_iterators.h"<br>
+#include "count_new.hpp"<br>
+#include "filesystem_test_helper.hpp"<br>
+<br>
+<br>
+int main() {<br>
+  // clang-format off<br>
+  struct {<br>
+    std::string input;<br>
+    std::string expect;<br>
+  } TestCases[] = {<br>
+      {"", ""},<br>
+      {"/a/b/c", "/a/b/c"},<br>
+      {"/a/b//c", "/a/b/c"},<br>
+      {"foo/./bar/..", "foo/"},<br>
+      {"foo/.///bar/../", "foo/"},<br>
+      {"/a/b/", "/a/b/"},<br>
+      {"a/b", "a/b"},<br>
+      {"a/b/.", "a/b/"},<br>
+      {"a/b/./", "a/b/"},<br>
+      {"a/..", "."},<br>
+      {".", "."},<br>
+      {"./", "."},<br>
+      {"./.", "."},<br>
+      {"./..", ".."},<br>
+      {"..", ".."},<br>
+      {"../..", "../.."},<br>
+      {"/../", "/"},<br>
+      {"/../..", "/"},<br>
+      {"/../../", "/"},<br>
+      {"..", ".."},<br>
+      {"../", ".."},<br>
+      {"/a/b/c/../", "/a/b/"},<br>
+      {"/a/b/./", "/a/b/"},<br>
+      {"/a/b/c/../d", "/a/b/d"},<br>
+      {"/a/b/c/../d/", "/a/b/d/"},<br>
+      {"//a/", "/a/"},<br>
+      {"//a/b/", "/a/b/"},<br>
+      {"//a/b/.", "/a/b/"},<br>
+      {"//a/..", "/"},<br>
+      ///===------------------------<wbr>------------------------------<wbr>---------===//<br>
+      /// Tests specifically for the clauses under [fs.path.generic]p6<br>
+      ///===------------------------<wbr>------------------------------<wbr>---------===//<br>
+      // p1: If the path is empty, stop.<br>
+      {"", ""},<br>
+      // p2: Replace each slash character in the root-name with a preferred<br>
+      // separator.<br>
+      {"NO_ROOT_NAME_ON_LINUX", "NO_ROOT_NAME_ON_LINUX"},<br>
+      // p3: Replace each directory-separator with a preferred-separator.<br>
+      // [ Note: The generic pathname grammar ([fs.path.generic]) defines<br>
+      //   directory-separator as one or more slashes and preferred-separators.<br>
+      //   â€” end note ]<br>
+      {"/", "/"},<br>
+      {"//", "/"},<br>
+      {"///", "/"},<br>
+      {"a/b", "a/b"},<br>
+      {"a//b", "a/b"},<br>
+      {"a///b", "a/b"},<br>
+      {"a/b/", "a/b/"},<br>
+      {"a/b//", "a/b/"},<br>
+      {"a/b///", "a/b/"},<br>
+      {"///a////b//////", "/a/b/"},<br>
+      // p4: Remove each dot filename and any immediately following directory<br>
+      // separators<br>
+      {"foo/.", "foo/"},<br>
+      {"foo/./bar/.", "foo/bar/"},<br>
+      {"./foo/././bar/./", "foo/bar/"},<br>
+      {".///foo//.////./bar/.///", "foo/bar/"},<br>
+      // p5: As long as any appear, remove a non-dot-dot filename immediately<br>
+      // followed by a directory-separator and a dot-dot filename, along with<br>
+      // any immediately following directory separator.<br>
+      {"foo/..", "."},<br>
+      {"foo/../", "."},<br>
+      {"foo/bar/..", "foo/"},<br>
+      {"foo/bar/../", "foo/"},<br>
+      {"foo/bar/../..", "."},<br>
+      {"foo/bar/../../", "."},<br>
+      {"foo/bar/baz/../..", "foo/"},<br>
+      {"foo/bar/baz/../../", "foo/"},<br>
+      {"foo/bar/./..", "foo/"},<br>
+      {"foo/bar/./../", "foo/"},<br>
+      // p6: If there is a root-directory, remove all dot-dot filenames and any<br>
+      // directory-separators immediately following them. [ Note: These dot-dot<br>
+      // filenames attempt to refer to nonexistent parent directories. â€” end note ]<br>
+      {"/..", "/"},<br>
+      {"/../", "/"},<br>
+      {"/foo/../..", "/"},<br>
+      {"/../foo", "/foo"},<br>
+      {"/../foo/../..", "/"},<br>
+      // p7: If the last filename is dot-dot, remove any trailing<br>
+      // directory-separator.<br>
+      {"../", ".."},<br>
+      {"../../", "../.."},<br>
+      {"foo/../bar/../..///", ".."},<br>
+      {"foo/../bar/..//..///../", "../.."},<br>
+      // p8: If the path is empty, add a dot<br>
+      {".", "."},<br>
+      {"./", "."},<br>
+      {"foo/..", "."}<br>
+  };<br>
+  // clang-format on<br>
+  int ID = 0;<br>
+  bool Failed = false;<br>
+  for (auto& TC : TestCases) {<br>
+    ++ID;<br>
+    fs::path p(TC.input);<br>
+    const fs::path output = p.lexically_normal();<br>
+    if (!PathEq(output, TC.expect)) {<br>
+      Failed = true;<br>
+      std::cerr << "TEST CASE #" << ID << " FAILED: \n";<br>
+      std::cerr << "  Input: '" << TC.input << "'\n";<br>
+      std::cerr << "  Expected: '" << TC.expect << "'\n";<br>
+      std::cerr << "  Output: '" << output.native() << "'";<br>
+      std::cerr << std::endl;<br>
+    }<br>
+  }<br>
+  return Failed;<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_relative_and_<wbr>proximate.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_relative_and_<wbr>proximate.pass.cpp?rev=329028&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_relative_and_<wbr>proximate.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.gen/<wbr>lexically_relative_and_<wbr>proximate.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,89 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// class path<br>
+<br>
+// path lexically_relative(const path& p) const;<br>
+// path lexically_proximate(const path& p) const;<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <vector><br>
+#include <iostream><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "test_iterators.h"<br>
+#include "count_new.hpp"<br>
+#include "filesystem_test_helper.hpp"<br>
+<br>
+<br>
+int main() {<br>
+  // clang-format off<br>
+  struct {<br>
+    std::string input;<br>
+    std::string base;<br>
+    std::string expect;<br>
+  } TestCases[] = {<br>
+      {"", "", "."},<br>
+      {"/", "a", ""},<br>
+      {"a", "/", ""},<br>
+      {"//net", "a", ""},<br>
+      {"a", "//net", ""},<br>
+      {"//net/", "//net", ""},<br>
+      {"//net", "//net/", ".."},<br>
+      {"//base", "a", ""},<br>
+      {"a", "a", "."},<br>
+      {"a/b", "a/b", "."},<br>
+      {"a/b/c/", "a/b/c/", "."},<br>
+      {"//net", "//net", "."},<br>
+      {"//net/", "//net/", "."},<br>
+      {"//net/a/b", "//net/a/b", "."},<br>
+      {"/a/d", "/a/b/c", "../../d"},<br>
+      {"/a/b/c", "/a/d", "../b/c"},<br>
+      {"a/b/c", "a", "b/c"},<br>
+      {"a/b/c", "a/b/c/x/y", "../.."},<br>
+      {"a/b/c", "a/b/c", "."},<br>
+      {"a/b", "c/d", "../../a/b"}<br>
+  };<br>
+  // clang-format on<br>
+  int ID = 0;<br>
+  bool Failed = false;<br>
+  for (auto& TC : TestCases) {<br>
+    ++ID;<br>
+    const fs::path p(TC.input);<br>
+    const fs::path output = p.lexically_relative(TC.base);<br>
+    auto ReportErr = [&](const char* Testing, fs::path const& Output,<br>
+                                              fs::path const& Expected) {<br>
+      Failed = true;<br>
+      std::cerr << "TEST CASE #" << ID << " FAILED: \n";<br>
+      std::cerr << "  Testing: " << Testing << "\n";<br>
+      std::cerr << "  Input: '" << TC.input << "'\n";<br>
+      std::cerr << "  Base: '" << TC.base << "'\n";<br>
+      std::cerr << "  Expected: '" << Expected << "'\n";<br>
+      std::cerr << "  Output: '" << Output.native() << "'";<br>
+      std::cerr << std::endl;<br>
+    };<br>
+    if (!PathEq(output, TC.expect))<br>
+      ReportErr("path::lexically_<wbr>relative", output, TC.expect);<br>
+    const fs::path proximate_output = p.lexically_proximate(TC.base)<wbr>;<br>
+    // [path.gen] lexically_proximate<br>
+    // Returns: If the value of lexically_relative(base) is not an empty path,<br>
+    // return it.Otherwise return *this.<br>
+    const fs::path proximate_expected = output.native().empty() ? p<br>
+        : output;<br>
+    if (!PathEq(proximate_expected, proximate_output))<br>
+      ReportErr("path::lexically_<wbr>proximate", proximate_output, proximate_expected);<br>
+  }<br>
+  return Failed;<br>
+}<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/generic_string_alloc.pass.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/generic_string_alloc.pass.<wbr>cpp?rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/generic_string_alloc.pass.<wbr>cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/generic_string_alloc.pass.<wbr>cpp Mon Apr  2 16:03:41 2018<br>
@@ -28,7 +28,6 @@<br>
 #include "min_allocator.h"<br>
 #include "filesystem_test_helper.hpp"<br>
<br>
-<br>
 MultiStringType longString = MKSTR("<wbr>abcdefghijklmnopqrstuvwxyzABCD<wbr>EFGHIJKLMNOPQRSTUVWXYZ/<wbr>123456789/<wbr>abcdefghijklmnopqrstuvwxyzABCD<wbr>EFGHIJKLMNOPQRSTUVWXYZabcdefgh<wbr>ijklmnopqrstuvwxyzABCDEFGHIJKL<wbr>MNOPQRSTUVWXYZ");<br>
<br>
<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/named_overloads.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/named_overloads.pass.cpp?<wbr>rev=329028&r1=329027&r2=<wbr>329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/named_overloads.pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.generic.<wbr>obs/named_overloads.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -30,7 +30,6 @@<br>
 #include "min_allocator.h"<br>
 #include "filesystem_test_helper.hpp"<br>
<br>
-<br>
 MultiStringType longString = MKSTR("<wbr>abcdefghijklmnopqrstuvwxyzABCD<wbr>EFGHIJKLMNOPQRSTUVWXYZ/<wbr>123456789/<wbr>abcdefghijklmnopqrstuvwxyzABCD<wbr>EFGHIJKLMNOPQRSTUVWXYZabcdefgh<wbr>ijklmnopqrstuvwxyzABCDEFGHIJKL<wbr>MNOPQRSTUVWXYZ");<br>
<br>
 int main()<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/remove_filename.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/remove_filename.<wbr>pass.cpp?rev=329028&r1=329027&<wbr>r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/remove_filename.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/remove_filename.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -23,7 +23,7 @@<br>
 #include "test_iterators.h"<br>
 #include "count_new.hpp"<br>
 #include "filesystem_test_helper.hpp"<br>
-<br>
+#include "verbose_assert.h"<br>
<br>
 struct RemoveFilenameTestcase {<br>
   const char* value;<br>
@@ -33,27 +33,29 @@ struct RemoveFilenameTestcase {<br>
 const RemoveFilenameTestcase TestCases[] =<br>
   {<br>
       {"", ""}<br>
-    , {"/", ""}<br>
-    , {"//", ""}<br>
-    , {"///", ""}<br>
+    , {"/", "/"}<br>
+    , {"//", "//"}<br>
+    , {"///", "///"}<br>
     , {"\\", ""}<br>
     , {".", ""}<br>
     , {"..", ""}<br>
     , {"/foo", "/"}<br>
-    , {"//foo", ""}<br>
-    , {"//foo/", ""}<br>
-    , {"//foo///", ""}<br>
-    , {"///foo", "/"}<br>
-    , {"///foo/", "///foo"}<br>
-    , {"/foo/", "/foo"}<br>
-    , {"/foo/.", "/foo"}<br>
-    , {"/foo/..", "/foo"}<br>
-    , {"/foo/////", "/foo"}<br>
+    , {"foo/bar", "foo/"}<br>
+    , {"foo/", "foo/"}<br>
+    , {"//foo", "//"}<br>
+    , {"//foo/", "//foo/"}<br>
+    , {"//foo///", "//foo///"}<br>
+    , {"///foo", "///"}<br>
+    , {"///foo/", "///foo/"}<br>
+    , {"/foo/", "/foo/"}<br>
+    , {"/foo/.", "/foo/"}<br>
+    , {"/foo/..", "/foo/"}<br>
+    , {"/foo/////", "/foo/////"}<br>
     , {"/foo\\\\", "/"}<br>
-    , {"/foo//\\/", "/foo//\\"}<br>
-    , {"///foo", "/"}<br>
+    , {"/foo//\\/", "/foo//\\/"}<br>
+    , {"///foo", "///"}<br>
     , {"file.txt", ""}<br>
-    , {"bar/../baz/./file.txt", "bar/../baz/."}<br>
+    , {"bar/../baz/./file.txt", "bar/../baz/./"}<br>
   };<br>
<br>
 int main()<br>
@@ -64,16 +66,8 @@ int main()<br>
     path p(p_orig);<br>
     assert(p == TC.value);<br>
     path& Ref = (p.remove_filename());<br>
-    assert(p == TC.expect);<br>
+    ASSERT_EQ(p, TC.expect) << DISPLAY(p_orig);<br>
     assert(&Ref == &p);<br>
-    {<br>
-      const path parentp = p_orig.parent_path();<br>
-      if (parentp == p_orig.root_name()) {<br>
-<br>
-        assert(p.empty());<br>
-      } else {<br>
-        assert(p == parentp);<br>
-      }<br>
-    }<br>
+    assert(!p.has_filename());<br>
   }<br>
 }<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/replace_filename.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/replace_filename.<wbr>pass.cpp?rev=329028&r1=329027&<wbr>r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/replace_filename.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/class.<wbr>path/path.member/path.<wbr>modifiers/replace_filename.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -23,7 +23,8 @@<br>
 #include "test_iterators.h"<br>
 #include "count_new.hpp"<br>
 #include "filesystem_test_helper.hpp"<br>
-<br>
+#include "assert_checkpoint.h"<br>
+#include "verbose_assert.h"<br>
<br>
 struct ReplaceFilenameTestcase {<br>
   const char* value;<br>
@@ -36,9 +37,9 @@ const ReplaceFilenameTestcase TestCases[<br>
       {"/foo", "/bar", "bar"}<br>
     , {"/foo", "/", ""}<br>
     , {"foo", "bar", "bar"}<br>
-    , {"/", "bar", "bar"}<br>
+    , {"/", "/bar", "bar"}<br>
     , {"\\", "bar", "bar"}<br>
-    , {"///", "bar", "bar"}<br>
+    , {"///", "///bar", "bar"}<br>
     , {"\\\\", "bar", "bar"}<br>
     , {"\\/\\", "\\/bar", "bar"}<br>
     , {".", "bar", "bar"}<br>
@@ -52,9 +53,11 @@ int main()<br>
   using namespace fs;<br>
   for (auto const & TC : TestCases) {<br>
     path p(TC.value);<br>
-    assert(p == TC.value);<br>
+    ASSERT_EQ(p, TC.value);<br>
     path& Ref = (p.replace_filename(TC.<wbr>filename));<br>
-    assert(p == TC.expect);<br>
+    ASSERT_EQ(p, TC.expect)<br>
+        << DISPLAY(TC.value)<br>
+        << DISPLAY(TC.filename);<br>
     assert(&Ref == &p);<br>
     // Tests Effects "as-if": remove_filename() append(filename)<br>
     {<br>
@@ -62,7 +65,7 @@ int main()<br>
       path replace(TC.filename);<br>
       p2.remove_filename();<br>
       p2 /= replace;<br>
-      assert(p2 == p);<br>
+      ASSERT_EQ(p, p2);<br>
     }<br>
   }<br>
 }<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.<wbr>enum/enum.perm_options.pass.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.perm_options.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.<wbr>enum/enum.perm_options.pass.<wbr>cpp?rev=329028&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.<wbr>enum/enum.perm_options.pass.<wbr>cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.<wbr>enum/enum.perm_options.pass.<wbr>cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,48 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// enum class perm_options;<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <cassert><br>
+#include <sys/stat.h><br>
+<br>
+#include "test_macros.h"<br>
+#include "check_bitmask_types.hpp"<br>
+<br>
+<br>
+constexpr fs::perm_options ME(int val) {<br>
+  return static_cast<fs::perm_options>(<wbr>val);<br>
+}<br>
+<br>
+int main() {<br>
+  typedef fs::perm_options E;<br>
+  static_assert(std::is_enum<E>:<wbr>:value, "");<br>
+<br>
+  // Check that E is a scoped enum by checking for conversions.<br>
+  typedef std::underlying_type<E>::type UT;<br>
+  static_assert(!std::is_<wbr>convertible<E, UT>::value, "");<br>
+<br>
+  static_assert(std::is_same<UT, unsigned char >::value, ""); // Implementation detail<br>
+<br>
+  typedef check_bitmask_type<E, E::replace, E::nofollow> BitmaskTester;<br>
+  assert(BitmaskTester::check())<wbr>;<br>
+<br>
+  static_assert(<br>
+        E::replace  == ME(1) &&<br>
+        E::add      == ME(2) &&<br>
+        E::remove   == ME(4) &&<br>
+        E::nofollow == ME(8),<br>
+        "Expected enumeration values do not match");<br>
+}<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.absolute/absolute.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.absolute/absolute.<wbr>pass.cpp?rev=329028&r1=329027&<wbr>r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.absolute/absolute.<wbr>pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.absolute/absolute.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -28,89 +28,30 @@ TEST_SUITE(filesystem_<wbr>absolute_path_test<br>
 TEST_CASE(absolute_signature_<wbr>test)<br>
 {<br>
     const path p; ((void)p);<br>
+    std::error_code ec;<br>
     ASSERT_NOT_NOEXCEPT(absolute(<wbr>p));<br>
-    ASSERT_NOT_NOEXCEPT(absolute(<wbr>p, p));<br>
+    ASSERT_NOT_NOEXCEPT(absolute(<wbr>p, ec));<br>
 }<br>
<br>
-// There are 4 cases is the proposal for absolute path.<br>
-// Each scope tests one of the cases.<br>
-TEST_CASE(absolute_path_test)<br>
-{<br>
-    // has_root_name() && has_root_directory()<br>
-    {<br>
-        const path p("//net/foo");<br>
-        const path base("//net/bar/baz");<br>
-        TEST_REQUIRE(p.has_root_name()<wbr>);<br>
-        TEST_REQUIRE(p.has_root_<wbr>directory());<br>
-        TEST_CHECK(p.is_absolute());<br>
-        path ret = absolute(p, base);<br>
-        TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret == p);<br>
-    }<br>
-    // !has_root_name() && has_root_directory()<br>
-    {<br>
-        const path p("/foo");<br>
-        const path base("//net/bar");<br>
-        TEST_REQUIRE(not p.has_root_name());<br>
-        TEST_REQUIRE(p.has_root_<wbr>directory());<br>
-        TEST_CHECK(p.is_absolute());<br>
-        // ensure absolute(base) is not recursively called<br>
-        TEST_REQUIRE(base.has_root_<wbr>name());<br>
-        TEST_REQUIRE(base.has_root_<wbr>directory());<br>
-<br>
-        path ret = absolute(p, base);<br>
-        TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret.has_root_name()<wbr>);<br>
-        TEST_CHECK(ret.root_name() == path("//net"));<br>
-        TEST_CHECK(ret.has_root_<wbr>directory());<br>
-        TEST_CHECK(ret.root_directory(<wbr>) == path("/"));<br>
-        TEST_CHECK(ret == path("//net/foo"));<br>
-    }<br>
-    // has_root_name() && !has_root_directory()<br>
-    {<br>
-        const path p("//net");<br>
-        const path base("//net/foo/bar");<br>
-        TEST_REQUIRE(p.has_root_name()<wbr>);<br>
-        TEST_REQUIRE(not p.has_root_directory());<br>
-        TEST_CHECK(not p.is_absolute());<br>
-        // absolute is called recursively on base. The following conditions<br>
-        // must be true for it to return base unmodified<br>
-        TEST_REQUIRE(base.has_root_<wbr>name());<br>
-        TEST_REQUIRE(base.has_root_<wbr>directory());<br>
-        path ret = absolute(p, base);<br>
-        const path expect("//net/foo/bar");<br>
-        TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret == path("//net/foo/bar"));<br>
-    }<br>
-    // !has_root_name() && !has_root_directory()<br>
-    {<br>
-        const path p("bar/baz");<br>
-        const path base("//net/foo");<br>
-        TEST_REQUIRE(not p.has_root_name());<br>
-        TEST_REQUIRE(not p.has_root_directory());<br>
-        TEST_REQUIRE(base.has_root_<wbr>name());<br>
-        TEST_REQUIRE(base.has_root_<wbr>directory());<br>
-<br>
-        path ret = absolute(p, base);<br>
-        TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret == path("//net/foo/bar/baz"));<br>
-    }<br>
-}<br>
<br>
-TEST_CASE(absolute_path_with_<wbr>default_base)<br>
+TEST_CASE(basic_test)<br>
 {<br>
-    const path testCases[] = {<br>
-        "//net/foo", //  has_root_name() &&  has_root_directory()<br>
-        "/foo",      // !has_root_name() &&  has_root_directory()<br>
-        "//net",     //  has_root_name() && !has_root_directory()<br>
-        "bar/baz"    // !has_root_name() && !has_root_directory()<br>
+    const fs::path cwd = fs::current_path();<br>
+    const struct {<br>
+      std::string input;<br>
+      std::string expect;<br>
+    } TestCases [] = {<br>
+        {"", cwd / ""},<br>
+        {"foo", cwd / "foo"},<br>
+        {"foo/", cwd / "foo/"},<br>
+        {"/already_absolute", "/already_absolute"}<br>
     };<br>
-    const path base = current_path();<br>
-    for (auto& p : testCases) {<br>
-        const path ret = absolute(p);<br>
-        const path expect = absolute(p, base);<br>
+    for (auto& TC : TestCases) {<br>
+        std::error_code ec = GetTestEC();<br>
+        const path ret = absolute(TC.input, ec);<br>
+        TEST_CHECK(!ec);<br>
         TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret == expect);<br>
+        TEST_CHECK(PathEq(ret, TC.expect));<br>
     }<br>
 }<br>
<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.canonical/<wbr>canonical.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.canonical/canonical.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.canonical/<wbr>canonical.pass.cpp?rev=329028&<wbr>r1=329027&r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.canonical/<wbr>canonical.pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.canonical/<wbr>canonical.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -11,9 +11,8 @@<br>
<br>
 // <experimental/filesystem><br>
<br>
-// path canonical(const path& p, const path& base = current_path());<br>
+// path canonical(const path& p);<br>
 // path canonical(const path& p, error_code& ec);<br>
-// path canonical(const path& p, const path& base, error_code& ec);<br>
<br>
 #include "filesystem_include.hpp"<br>
 #include <type_traits><br>
@@ -25,6 +24,15 @@<br>
<br>
 using namespace fs;<br>
<br>
+struct CWDGuard {<br>
+  path OldCWD;<br>
+  CWDGuard() : OldCWD(fs::current_path()) { }<br>
+  ~CWDGuard() { fs::current_path(OldCWD); }<br>
+<br>
+  CWDGuard(CWDGuard const&) = delete;<br>
+  CWDGuard& operator=(CWDGuard const&) = delete;<br>
+};<br>
+<br>
 TEST_SUITE(filesystem_<wbr>canonical_path_test_suite)<br>
<br>
 TEST_CASE(signature_test)<br>
@@ -32,15 +40,14 @@ TEST_CASE(signature_test)<br>
     const path p; ((void)p);<br>
     std::error_code ec; ((void)ec);<br>
     ASSERT_NOT_NOEXCEPT(canonical(<wbr>p));<br>
-    ASSERT_NOT_NOEXCEPT(canonical(<wbr>p, p));<br>
     ASSERT_NOT_NOEXCEPT(canonical(<wbr>p, ec));<br>
-    ASSERT_NOT_NOEXCEPT(canonical(<wbr>p, p, ec));<br>
 }<br>
<br>
 // There are 4 cases is the proposal for absolute path.<br>
 // Each scope tests one of the cases.<br>
 TEST_CASE(test_canonical)<br>
 {<br>
+    CWDGuard guard;<br>
     // has_root_name() && has_root_directory()<br>
     const path Root = StaticEnv::Root;<br>
     const path RootName = Root.filename();<br>
@@ -65,54 +72,51 @@ TEST_CASE(test_canonical)<br>
         { SymlinkName, StaticEnv::File, StaticEnv::Root}<br>
     };<br>
     for (auto& TC : testCases) {<br>
-        std::error_code ec;<br>
-        const path ret = canonical(TC.p, TC.base, ec);<br>
+        std::error_code ec = GetTestEC();<br>
+        fs::current_path(TC.base);<br>
+        const path ret = canonical(TC.p, ec);<br>
         TEST_REQUIRE(!ec);<br>
-        const path ret2 = canonical(TC.p, TC.base);<br>
-        TEST_CHECK(ret == TC.expect);<br>
-        TEST_CHECK(ret == ret2);<br>
+        const path ret2 = canonical(TC.p);<br>
+        TEST_CHECK(PathEq(ret, TC.expect));<br>
+        TEST_CHECK(PathEq(ret, ret2));<br>
         TEST_CHECK(ret.is_absolute());<br>
     }<br>
 }<br>
<br>
 TEST_CASE(test_dne_path)<br>
 {<br>
-    std::error_code ec;<br>
+    std::error_code ec = GetTestEC();<br>
     {<br>
         const path ret = canonical(StaticEnv::DNE, ec);<br>
-        TEST_REQUIRE(ec);<br>
-        TEST_CHECK(ret == path{});<br>
-    }<br>
-    ec.clear();<br>
-    {<br>
-        const path ret = canonical(StaticEnv::DNE, StaticEnv::Root, ec);<br>
+        TEST_CHECK(ec != GetTestEC());<br>
         TEST_REQUIRE(ec);<br>
         TEST_CHECK(ret == path{});<br>
     }<br>
     {<br>
         TEST_CHECK_THROW(filesystem_<wbr>error, canonical(StaticEnv::DNE));<br>
-        TEST_CHECK_THROW(filesystem_<wbr>error, canonical(StaticEnv::DNE, StaticEnv::Root));<br>
     }<br>
 }<br>
<br>
 TEST_CASE(test_exception_<wbr>contains_paths)<br>
 {<br>
 #ifndef TEST_HAS_NO_EXCEPTIONS<br>
+    CWDGuard guard;<br>
     const path p = "blabla/dne";<br>
-    const path base = StaticEnv::Root;<br>
     try {<br>
-        canonical(p, base);<br>
+        canonical(p);<br>
         TEST_REQUIRE(false);<br>
     } catch (filesystem_error const& err) {<br>
         TEST_CHECK(err.path1() == p);<br>
-        TEST_CHECK(err.path2() == base);<br>
+        // libc++ provides the current path as the second path in the exception<br>
+        LIBCPP_ONLY(TEST_CHECK(err.<wbr>path2() == current_path()));<br>
     }<br>
+    fs::current_path(StaticEnv::<wbr>Dir);<br>
     try {<br>
         canonical(p);<br>
         TEST_REQUIRE(false);<br>
     } catch (filesystem_error const& err) {<br>
         TEST_CHECK(err.path1() == p);<br>
-        TEST_CHECK(err.path2() == current_path());<br>
+        LIBCPP_ONLY(TEST_CHECK(err.<wbr>path2() == StaticEnv::Dir));<br>
     }<br>
 #endif<br>
 }<br>
<br>
Modified: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.last_write_time/<wbr>last_write_time.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.last_write_time/last_write_time.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.last_write_time/<wbr>last_write_time.pass.cpp?rev=<wbr>329028&r1=329027&r2=329028&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.last_write_time/<wbr>last_write_time.pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.last_write_time/<wbr>last_write_time.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -17,7 +17,6 @@<br>
 // void last_write_time(const path& p, file_time_type new_type,<br>
 //                      std::error_code& ec) noexcept;<br>
<br>
-<br>
 #include "filesystem_include.hpp"<br>
 #include <type_traits><br>
 #include <chrono><br>
@@ -33,7 +32,6 @@<br>
<br>
 using namespace fs;<br>
<br>
-<br>
 std::pair<std::time_t, std::time_t> GetTimes(path const& p) {<br>
     using Clock = file_time_type::clock;<br>
     struct ::stat st;<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<wbr>proximate.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.proximate/proximate.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<wbr>proximate.pass.cpp?rev=329028&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<wbr>proximate.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.proximate/<wbr>proximate.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,125 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// path proximate(const path& p, error_code &ec)<br>
+// path proximate(const path& p, const path& base = current_path())<br>
+// path proximate(const path& p, const path& base, error_code& ec);<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <vector><br>
+#include <iostream><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "test_iterators.h"<br>
+#include "count_new.hpp"<br>
+#include "rapid-cxx-test.hpp"<br>
+#include "filesystem_test_helper.hpp"<br>
+<br>
+<br>
+static int count_path_elems(const fs::path& p) {<br>
+  int count = 0;<br>
+  for (auto& elem : p) {<br>
+    if (elem != "/" && elem != "")<br>
+      ++count;<br>
+  }<br>
+  return count;<br>
+}<br>
+<br>
+TEST_SUITE(filesystem_<wbr>proximate_path_test_suite)<br>
+<br>
+<br>
+TEST_CASE(signature_test)<br>
+{<br>
+    using fs::path;<br>
+    const path p; ((void)p);<br>
+    std::error_code ec; ((void)ec);<br>
+    ASSERT_NOT_NOEXCEPT(proximate(<wbr>p));<br>
+    ASSERT_NOT_NOEXCEPT(proximate(<wbr>p, p));<br>
+    ASSERT_NOT_NOEXCEPT(proximate(<wbr>p, ec));<br>
+    ASSERT_NOT_NOEXCEPT(proximate(<wbr>p, p, ec));<br>
+}<br>
+<br>
+TEST_CASE(basic_test) {<br>
+  using fs::path;<br>
+  const path cwd = fs::current_path();<br>
+  const path parent_cwd = cwd.parent_path();<br>
+  const path curdir = cwd.filename();<br>
+  TEST_REQUIRE(!cwd.native().<wbr>empty());<br>
+  int cwd_depth = count_path_elems(cwd);<br>
+  path dot_dot_to_root;<br>
+  for (int i=0; i < cwd_depth; ++i)<br>
+    dot_dot_to_root /= "..";<br>
+  path relative_cwd = cwd.native().substr(1);<br>
+  // clang-format off<br>
+  struct {<br>
+    std::string input;<br>
+    std::string base;<br>
+    std::string expect;<br>
+  } TestCases[] = {<br>
+      {"", "", "."},<br>
+      {cwd, "a", ".."},<br>
+      {parent_cwd, "a", "../.."},<br>
+      {"a", cwd, "a"},<br>
+      {"a", parent_cwd, "fs.op.proximate/a"},<br>
+      {"/", "a", dot_dot_to_root / ".."},<br>
+      {"/", "a/b", dot_dot_to_root / "../.."},<br>
+      {"/", "a/b/", dot_dot_to_root / "../../.."},<br>
+      {"a", "/", relative_cwd / "a"},<br>
+      {"a/b", "/", relative_cwd / "a/b"},<br>
+      {"a", "/net", ".." / relative_cwd / "a"},<br>
+      {"//net/", "//net", "/net/"},<br>
+      {"//net", "//net/", ".."},<br>
+      {"//net", "//net", "."},<br>
+      {"//net/", "//net/", "."},<br>
+      {"//base", "a", dot_dot_to_root / "../base"},<br>
+      {"a", "a", "."},<br>
+      {"a/b", "a/b", "."},<br>
+      {"a/b/c/", "a/b/c/", "."},<br>
+      {"//net/a/b", "//net/a/b", "."},<br>
+      {"/a/d", "/a/b/c", "../../d"},<br>
+      {"/a/b/c", "/a/d", "../b/c"},<br>
+      {"a/b/c", "a", "b/c"},<br>
+      {"a/b/c", "a/b/c/x/y", "../.."},<br>
+      {"a/b/c", "a/b/c", "."},<br>
+      {"a/b", "c/d", "../../a/b"}<br>
+  };<br>
+  // clang-format on<br>
+  int ID = 0;<br>
+  for (auto& TC : TestCases) {<br>
+    ++ID;<br>
+    std::error_code ec = GetTestEC();<br>
+    fs::path p(TC.input);<br>
+    const fs::path output = fs::proximate(p, TC.base, ec);<br>
+    TEST_CHECK(!ec);<br>
+    TEST_CHECK(PathEq(output, TC.expect));<br>
+    if (!PathEq(output, TC.expect)) {<br>
+      const path canon_input = fs::weakly_canonical(TC.input)<wbr>;<br>
+      const path canon_base = fs::weakly_canonical(TC.base);<br>
+      const path lexically_p = canon_input.lexically_<wbr>proximate(canon_base);<br>
+      std::cerr << "TEST CASE #" << ID << " FAILED: \n";<br>
+      std::cerr << "  Input: '" << TC.input << "'\n";<br>
+      std::cerr << "  Base: '" << TC.base << "'\n";<br>
+      std::cerr << "  Expected: '" << TC.expect << "'\n";<br>
+      std::cerr << "  Output:   '" << output.native() << "'\n";<br>
+      std::cerr << "  Lex Prox: '" << lexically_p.native() << "'\n";<br>
+      std::cerr << "  Canon Input: " <<  canon_input << "\n";<br>
+      std::cerr << "  Canon Base: " << canon_base << "\n";<br>
+<br>
+      std::cerr << std::endl;<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+TEST_SUITE_END()<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/relative.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.relative/relative.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/relative.<wbr>pass.cpp?rev=329028&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/relative.<wbr>pass.cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.relative/relative.<wbr>pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,78 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// path proximate(const path& p, error_code &ec)<br>
+// path proximate(const path& p, const path& base = current_path())<br>
+// path proximate(const path& p, const path& base, error_code& ec);<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <vector><br>
+#include <iostream><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "test_iterators.h"<br>
+#include "count_new.hpp"<br>
+#include "rapid-cxx-test.hpp"<br>
+#include "filesystem_test_helper.hpp"<br>
+<br>
+<br>
+TEST_SUITE(filesystem_<wbr>proximate_path_test_suite)<br>
+<br>
+TEST_CASE(test_signature) {<br>
+<br>
+}<br>
+int main() {<br>
+  // clang-format off<br>
+  struct {<br>
+    std::string input;<br>
+    std::string expect;<br>
+  } TestCases[] = {<br>
+      {"", fs::current_path()},<br>
+      {".", fs::current_path()},<br>
+      {StaticEnv::File, StaticEnv::File},<br>
+      {StaticEnv::Dir, StaticEnv::Dir},<br>
+      {StaticEnv::SymlinkToDir, StaticEnv::Dir},<br>
+      {StaticEnv::SymlinkToDir / "dir2/.", StaticEnv::Dir / "dir2"},<br>
+      // FIXME? If the trailing separator occurs in a part of the path that exists,<br>
+      // it is ommitted. Otherwise it is added to the end of the result.<br>
+      {StaticEnv::SymlinkToDir / "dir2/./", StaticEnv::Dir / "dir2"},<br>
+      {StaticEnv::SymlinkToDir / "dir2/DNE/./", StaticEnv::Dir / "dir2/DNE/"},<br>
+      {StaticEnv::SymlinkToDir / "dir2", StaticEnv::Dir2},<br>
+      {StaticEnv::SymlinkToDir / "dir2/../dir2/DNE/..", StaticEnv::Dir2 / ""},<br>
+      {StaticEnv::SymlinkToDir / "dir2/dir3/../DNE/DNE2", StaticEnv::Dir2 / "DNE/DNE2"},<br>
+      {StaticEnv::Dir / "../dir1", StaticEnv::Dir},<br>
+      {StaticEnv::Dir / "./.", StaticEnv::Dir},<br>
+      {StaticEnv::Dir / "DNE/../foo", StaticEnv::Dir / "foo"}<br>
+  };<br>
+  // clang-format on<br>
+  int ID = 0;<br>
+  bool Failed = false;<br>
+  for (auto& TC : TestCases) {<br>
+    ++ID;<br>
+    fs::path p(TC.input);<br>
+    const fs::path output = fs::weakly_canonical(p);<br>
+    if (output != TC.expect) {<br>
+      Failed = true;<br>
+      std::cerr << "TEST CASE #" << ID << " FAILED: \n";<br>
+      std::cerr << "  Input: '" << TC.input << "'\n";<br>
+      std::cerr << "  Expected: '" << TC.expect << "'\n";<br>
+      std::cerr << "  Output: '" << output.native() << "'";<br>
+      std::cerr << std::endl;<br>
+    }<br>
+  }<br>
+  return Failed;<br>
+}<br>
+<br>
+TEST_SUITE_END()<br>
<br>
Removed: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.system_complete/<wbr>system_complete.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.system_complete/system_complete.pass.cpp?rev=329027&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.system_complete/<wbr>system_complete.pass.cpp?rev=<wbr>329027&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.system_complete/<wbr>system_complete.pass.cpp (original)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.system_complete/<wbr>system_complete.pass.cpp (removed)<br>
@@ -1,58 +0,0 @@<br>
-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
-//<br>
-//                     The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is dual licensed under the MIT and the University of Illinois Open<br>
-// Source Licenses. See LICENSE.TXT for details.<br>
-//<br>
-//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
-<br>
-// UNSUPPORTED: c++98, c++03<br>
-<br>
-// <experimental/filesystem><br>
-<br>
-// path system_complete(const path& p);<br>
-// path system_complete(const path& p, error_code& ec);<br>
-<br>
-// Note: For POSIX based operating systems, 'system_complete(p)' has the<br>
-// same semantics as 'absolute(p, current_path())'.<br>
-<br>
-#include "filesystem_include.hpp"<br>
-#include <type_traits><br>
-#include <cassert><br>
-<br>
-#include "test_macros.h"<br>
-#include "rapid-cxx-test.hpp"<br>
-#include "filesystem_test_helper.hpp"<br>
-<br>
-using namespace fs;<br>
-<br>
-TEST_SUITE(filesystem_system_<wbr>complete_test_suite)<br>
-<br>
-TEST_CASE(signature_test)<br>
-{<br>
-    const path p; ((void)p);<br>
-    std::error_code ec; ((void)ec);<br>
-    ASSERT_NOT_NOEXCEPT(system_<wbr>complete(p));<br>
-    ASSERT_NOT_NOEXCEPT(system_<wbr>complete(p, ec));<br>
-}<br>
-<br>
-<br>
-TEST_CASE(basic_system_<wbr>complete_tests)<br>
-{<br>
-    const path testCases[] = {<br>
-        "//net/foo", //  has_root_name() &&  has_root_directory()<br>
-        "/foo",      // !has_root_name() &&  has_root_directory()<br>
-        "//net",     //  has_root_name() && !has_root_directory()<br>
-        "bar/baz"    // !has_root_name() && !has_root_directory()<br>
-    };<br>
-    const path base = current_path();<br>
-    for (auto& p : testCases) {<br>
-        const path ret = system_complete(p);<br>
-        const path expect = absolute(p, base);<br>
-        TEST_CHECK(ret.is_absolute());<br>
-        TEST_CHECK(ret == expect);<br>
-    }<br>
-}<br>
-<br>
-TEST_SUITE_END()<br>
<br>
Added: libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<wbr>weakly_canonical.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<wbr>weakly_canonical.pass.cpp?rev=<wbr>329028&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<wbr>weakly_canonical.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/<wbr>experimental/filesystem/fs.op.<wbr>funcs/fs.op.weakly_canonical/<wbr>weakly_canonical.pass.cpp Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,76 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03<br>
+<br>
+// <experimental/filesystem><br>
+<br>
+// path weakly_canonical(const path& p);<br>
+// path weakly_canonical(const path& p, error_code& ec);<br>
+<br>
+#include "filesystem_include.hpp"<br>
+#include <type_traits><br>
+#include <vector><br>
+#include <iostream><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+#include "test_iterators.h"<br>
+#include "count_new.hpp"<br>
+#include "filesystem_test_helper.hpp"<br>
+<br>
+<br>
+int main() {<br>
+  // clang-format off<br>
+  struct {<br>
+    std::string input;<br>
+    std::string expect;<br>
+  } TestCases[] = {<br>
+      {"", fs::current_path()},<br>
+      {".", fs::current_path()},<br>
+      {"/", "/"},<br>
+      {"/foo", "/foo"},<br>
+      {"/.", "/"},<br>
+      {"/./", "/"},<br>
+      {"a/b", fs::current_path() / "a/b"},<br>
+      {"a", fs::current_path() / "a"},<br>
+      {"a/b/", fs::current_path() / "a/b/"},<br>
+      {StaticEnv::File, StaticEnv::File},<br>
+      {StaticEnv::Dir, StaticEnv::Dir},<br>
+      {StaticEnv::SymlinkToDir, StaticEnv::Dir},<br>
+      {StaticEnv::SymlinkToDir / "dir2/.", StaticEnv::Dir / "dir2"},<br>
+      // FIXME? If the trailing separator occurs in a part of the path that exists,<br>
+      // it is ommitted. Otherwise it is added to the end of the result.<br>
+      {StaticEnv::SymlinkToDir / "dir2/./", StaticEnv::Dir / "dir2"},<br>
+      {StaticEnv::SymlinkToDir / "dir2/DNE/./", StaticEnv::Dir / "dir2/DNE/"},<br>
+      {StaticEnv::SymlinkToDir / "dir2", StaticEnv::Dir2},<br>
+      {StaticEnv::SymlinkToDir / "dir2/../dir2/DNE/..", StaticEnv::Dir2 / ""},<br>
+      {StaticEnv::SymlinkToDir / "dir2/dir3/../DNE/DNE2", StaticEnv::Dir2 / "DNE/DNE2"},<br>
+      {StaticEnv::Dir / "../dir1", StaticEnv::Dir},<br>
+      {StaticEnv::Dir / "./.", StaticEnv::Dir},<br>
+      {StaticEnv::Dir / "DNE/../foo", StaticEnv::Dir / "foo"}<br>
+  };<br>
+  // clang-format on<br>
+  int ID = 0;<br>
+  bool Failed = false;<br>
+  for (auto& TC : TestCases) {<br>
+    ++ID;<br>
+    fs::path p(TC.input);<br>
+    const fs::path output = fs::weakly_canonical(p);<br>
+    if (!PathEq(output, TC.expect)) {<br>
+      Failed = true;<br>
+      std::cerr << "TEST CASE #" << ID << " FAILED: \n";<br>
+      std::cerr << "  Input: '" << TC.input << "'\n";<br>
+      std::cerr << "  Expected: '" << TC.expect << "'\n";<br>
+      std::cerr << "  Output: '" << output.native() << "'";<br>
+      std::cerr << std::endl;<br>
+    }<br>
+  }<br>
+  return Failed;<br>
+}<br>
<br>
Modified: libcxx/trunk/test/support/<wbr>filesystem_test_helper.hpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/filesystem_test_helper.hpp?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/<wbr>support/filesystem_test_<wbr>helper.hpp?rev=329028&r1=<wbr>329027&r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/support/<wbr>filesystem_test_helper.hpp (original)<br>
+++ libcxx/trunk/test/support/<wbr>filesystem_test_helper.hpp Mon Apr  2 16:03:41 2018<br>
@@ -9,7 +9,6 @@<br>
 #include <random><br>
 #include <chrono><br>
<br>
-<br>
 // static test helpers<br>
<br>
 #ifndef LIBCXX_FILESYSTEM_STATIC_TEST_<wbr>ROOT<br>
@@ -400,4 +399,8 @@ void SleepFor(std::chrono::seconds dur)<br>
         ;<br>
 }<br>
<br>
+inline bool PathEq(fs::path const& LHS, fs::path const& RHS) {<br>
+  return LHS.native() == RHS.native();<br>
+}<br>
+<br>
 #endif /* FILESYSTEM_TEST_HELPER_HPP */<br>
<br>
Added: libcxx/trunk/test/support/<wbr>verbose_assert.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/verbose_assert.h?rev=329028&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/test/<wbr>support/verbose_assert.h?rev=<wbr>329028&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/support/<wbr>verbose_assert.h (added)<br>
+++ libcxx/trunk/test/support/<wbr>verbose_assert.h Mon Apr  2 16:03:41 2018<br>
@@ -0,0 +1,222 @@<br>
+#ifndef TEST_SUPPORT_VERBOSE_ASSERT<br>
+#define TEST_SUPPORT_VERBOSE_ASSERT<br>
+<br>
+#include <iostream><br>
+#include <cstdio><br>
+#include <sstream><br>
+#include <string><br>
+#include "test_macros.h"<br>
+<br>
+namespace verbose_assert {<br>
+<br>
+typedef std::basic_ostream<char>&(<wbr>EndLType)(std::basic_ostream<<wbr>char>&);<br>
+<br>
+template <class Stream, class Tp,<br>
+    class = decltype(std::declval<Stream&><wbr>() << std::declval<Tp const&>())><br>
+std::true_type IsStreamableImp(int);<br>
+template <class Stream, class Tp> std::false_type IsStreamableImp(long);<br>
+<br>
+template <class Stream, class Tp><br>
+struct IsStreamable : decltype(IsStreamableImp<<wbr>Stream, Tp>(0)) {};<br>
+<br>
+template <class Tp, int ST = (IsStreamable<decltype(std::<wbr>cerr), Tp>::value ? 1<br>
+        : (IsStreamable<decltype(std::<wbr>wcerr), Tp>::value ? 2 : -1))><br>
+struct SelectStream {<br>
+  static_assert(ST == -1, "specialization required for ST != -1");<br>
+  static void Print(Tp const&) { std::clog << "Value Not Streamable!\n"; }<br>
+};<br>
+<br>
+template <class Tp><br>
+struct SelectStream<Tp, 1> {<br>
+  static void Print(Tp const& val) { std::cerr << val; }<br>
+};<br>
+<br>
+template <class Tp><br>
+struct SelectStream<Tp, 2> {<br>
+  static void Print(Tp const& val) { std::wcerr << val; }<br>
+};<br>
+<br>
+struct AssertData {<br>
+  AssertData(const char* xcheck, const char* xfile, const char* xfunc,<br>
+             unsigned long xline, bool xpassed = true)<br>
+      : passed(xpassed), check(xcheck), file(xfile), func(xfunc), line(xline),<br>
+        msg() {}<br>
+<br>
+  AssertData& SetFailed(std::string xmsg = std::string()) {<br>
+    msg = xmsg;<br>
+    passed = false;<br>
+    return *this;<br>
+  }<br>
+<br>
+  void PrintFailed() const {<br>
+    std::fprintf(stderr, "%s:%lu %s: Assertion '%s' failed.\n", file, line,<br>
+                 func, check);<br>
+    if (!msg.empty())<br>
+      std::fprintf(stderr, "%s\n", msg.data());<br>
+  }<br>
+<br>
+  bool passed;<br>
+  const char* check;<br>
+  const char* file;<br>
+  const char* func;<br>
+  unsigned long line;<br>
+  std::string msg;<br>
+};<br>
+<br>
+// AssertHandler is the class constructed by failing CHECK macros. AssertHandler<br>
+// will log information about the failures and abort when it is destructed.<br>
+class AssertHandler {<br>
+public:<br>
+  AssertHandler(AssertData const& Data)<br>
+      : passed(Data.passed) {<br>
+    if (!passed)<br>
+      Data.PrintFailed();<br>
+  }<br>
+<br>
+  ~AssertHandler() TEST_NOEXCEPT_FALSE {<br>
+    if (!passed) {<br>
+      error_log << std::endl;<br>
+      std::abort();<br>
+    }<br>
+  }<br>
+<br>
+  class LogType {<br>
+    friend class AssertHandler;<br>
+<br>
+    template <class Tp><br>
+    friend LogType& operator<<(LogType& log, Tp const& value) {<br>
+      if (!log.is_disabled) {<br>
+        SelectStream<Tp>::Print(value)<wbr>;<br>
+      }<br>
+      return log;<br>
+    }<br>
+<br>
+    friend LogType& operator<<(LogType& log, EndLType* m) {<br>
+      if (!log.is_disabled) {<br>
+        SelectStream<EndLType*>::<wbr>Print(m);<br>
+      }<br>
+      return log;<br>
+    }<br>
+<br>
+  private:<br>
+    LogType(bool disable) : is_disabled(disable) {}<br>
+    bool is_disabled;<br>
+<br>
+    LogType(LogType const&);<br>
+    LogType& operator=(LogType const&);<br>
+  };<br>
+<br>
+  LogType& GetLog() {<br>
+    if (passed)<br>
+      return null_log;<br>
+    return error_log;<br>
+  }<br>
+<br>
+private:<br>
+  static LogType null_log;<br>
+  static LogType error_log;<br>
+<br>
+  AssertHandler& operator=(const AssertHandler&) = delete;<br>
+  AssertHandler(const AssertHandler&) = delete;<br>
+  AssertHandler() = delete;<br>
+<br>
+private:<br>
+  bool passed;<br>
+};<br>
+<br>
+AssertHandler::LogType AssertHandler::null_log(true);<br>
+AssertHandler::LogType AssertHandler::error_log(<wbr>false);<br>
+<br>
+template <class It1><br>
+std::string PrintRange(const char* Name, It1 F, It1 E) {<br>
+  std::stringstream ss;<br>
+  ss << "  " << Name << " = [";<br>
+  while (F != E) {<br>
+    ss << *F;<br>
+    ++F;<br>
+    if (F != E)<br>
+      ss << ", ";<br>
+  }<br>
+  ss << "]\n";<br>
+  return ss.str();<br>
+}<br>
+<br>
+template <class Tp, class Up><br>
+std::string PrintMismatch(Tp const& LHS, Up const& RHS, int Elem) {<br>
+  std::stringstream ss;<br>
+  ss << "  Element " << Elem << " mismatched: `" << LHS << "` != `" << RHS<br>
+     << "`!\n";<br>
+  return ss.str();<br>
+};<br>
+<br>
+struct EqualToComp {<br>
+  template <class Tp, class Up><br>
+  bool operator()(Tp const& LHS, Up const& RHS) const {<br>
+    return LHS == RHS;<br>
+  }<br>
+};<br>
+<br>
+template <class It1, class It2, class Comp><br>
+AssertData CheckCollectionsEqual(It1 F1, It1 E1, It2 F2, It2 E2,<br>
+                                 AssertData Data, Comp C = EqualToComp()) {<br>
+  const It1 F1Orig = F1;<br>
+  const It2 F2Orig = F2;<br>
+  bool Failed = false;<br>
+  std::string ErrorMsg;<br>
+  int Idx = 0;<br>
+  while (F1 != E1 && F2 != E2) {<br>
+    if (!(C(*F1, *F2))) {<br>
+      ErrorMsg += PrintMismatch(*F1, *F2, Idx);<br>
+      Failed = true;<br>
+      break;<br>
+    }<br>
+    ++Idx;<br>
+    ++F1;<br>
+    ++F2;<br>
+  }<br>
+  if (!Failed && (F1 != E1 || F2 != E2)) {<br>
+    ErrorMsg += "  Ranges have different sizes!\n";<br>
+    Failed = true;<br>
+  }<br>
+  if (Failed) {<br>
+    ErrorMsg += PrintRange("LHS", F1Orig, E1);<br>
+    ErrorMsg += PrintRange("RHS", F2Orig, E2);<br>
+    Data.SetFailed(ErrorMsg);<br>
+  }<br>
+  return Data;<br>
+}<br>
+} // namespace verbose_assert<br>
+<br>
+#ifdef __GNUC__<br>
+#define ASSERT_FN_NAME() __PRETTY_FUNCTION__<br>
+#else<br>
+#define ASSERT_FN_NAME() __func__<br>
+#endif<br>
+<br>
+#define DISPLAY(...) "    " #__VA_ARGS__ " = " << (__VA_ARGS__) << "\n"<br>
+<br>
+#define ASSERT(...)                                                            \<br>
+  ::verbose_assert::<wbr>AssertHandler(::verbose_<wbr>assert::AssertData(                \<br>
+    #__VA_ARGS__, __FILE__, ASSERT_FN_NAME(), __LINE__,(__VA_ARGS__))).<wbr>GetLog()<br>
+<br>
+#define ASSERT_EQ(LHS, RHS) \<br>
+  ASSERT(LHS == RHS) << DISPLAY(LHS) << DISPLAY(RHS)<br>
+#define ASSERT_NEQ(LHS, RHS) \<br>
+  ASSERT(LHS != RHS) << DISPLAY(LHS) << DISPLAY(RHS)<br>
+#define ASSERT_PRED(PRED, LHS, RHS) \<br>
+  ASSERT(PRED(LHS, RHS)) << DISPLAY(LHS) << DISPLAY(RHS)<br>
+<br>
+#define ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, Comp)                        \<br>
+  (::verbose_assert::<wbr>AssertHandler(                                            \<br>
+       ::verbose_assert::<wbr>CheckCollectionsEqual(                                \<br>
+           F1, E1, F2, E2,                                                     \<br>
+           ::verbose_assert::AssertData("<wbr>CheckCollectionsEqual(" #F1 ", " #E1  \<br>
+                                        ", " #F2 ", " #E2 ")",                 \<br>
+                                        __FILE__, ASSERT_FN_NAME(), __LINE__), \<br>
+           Comp))                                                              \<br>
+       .GetLog())<br>
+<br>
+#define ASSERT_COLLECTION_EQ(F1, E1, F2, E2)                                   \<br>
+  ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, ::verbose_assert::EqualToComp(<wbr>))<br>
+<br>
+#endif<br>
<br>
Modified: libcxx/trunk/www/cxx1z_status.<wbr>html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/www/<wbr>cxx1z_status.html?rev=329028&<wbr>r1=329027&r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/www/cxx1z_status.<wbr>html (original)<br>
+++ libcxx/trunk/www/cxx1z_status.<wbr>html Mon Apr  2 16:03:41 2018<br>
@@ -111,7 +111,7 @@<br>
        <tr><td><a href="<a href="https://wg21.link/p0180r2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0180r2</a>">p0180r2</a></td><td><wbr>LWG</td><td>Reserve a New Library Namespace for Future Standardization</td><td>Oulu</<wbr>td><td><i>Nothing to do</i></td><td>n/a</td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/p0181r1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0181r1</a>">p0181r1</a></td><td><wbr>LWG</td><td>Ordered by Default</td><td>Oulu</td><td><<wbr>i>Removed in Kona</i></td><td>n/a</td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/p0209r2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0209r2</a>">p0209r2</a></td><td><wbr>LWG</td><td>make_from_tuple: apply for construction</td><td>Oulu</td><wbr><td>Complete</td><td>3.9</td><<wbr>/tr><br>
-       <tr><td><a href="<a href="https://wg21.link/p0219r1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0219r1</a>">p0219r1</a></td><td><wbr>LWG</td><td>Relative Paths for Filesystem</td><td>Oulu</td><<wbr>td></td><td></td></tr><br>
+       <tr><td><a href="<a href="https://wg21.link/p0219r1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0219r1</a>">p0219r1</a></td><td><wbr>LWG</td><td>Relative Paths for Filesystem</td><td>Oulu</td><<wbr>td>Complete</td><td>7.0</td></<wbr>tr><br>
        <tr><td><a href="<a href="https://wg21.link/p0254r2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0254r2</a>">p0254r2</a></td><td><wbr>LWG</td><td>Integrating std::string_view and std::string</td><td>Oulu</td><<wbr>td>Complete</td><td>4.0</td></<wbr>tr><br>
        <tr><td><a href="<a href="https://wg21.link/p0258r2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0258r2</a>">p0258r2</a></td><td><wbr>LWG</td><td>has_unique_object_<wbr>representations</td><td>Oulu</<wbr>td><td>Complete</td><td>6.0</<wbr>td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/p0295r0" rel="noreferrer" target="_blank">https://wg21.link/<wbr>p0295r0</a>">p0295r0</a></td><td><wbr>LWG</td><td>Adopt Selected Library Fundamentals V2 Components for C++17</td><td>Oulu</td><td><wbr>Complete</td><td>4.0</td></tr><br>
@@ -153,7 +153,7 @@<br>
        <tr><td><a href="<a href="https://wg21.link/P0433R2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0433R2</a>">P0433R2</a></td><td><wbr>LWG</td><td>Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library</td><td>Kona</td><td><<wbr>i>In progress</i></td><td>7.0</td><<wbr>/tr><br>
        <tr><td><a href="<a href="https://wg21.link/P0452R1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0452R1</a>">P0452R1</a></td><td><wbr>LWG</td><td>Unifying &lt;numeric&gt; Parallel Algorithms</td><td>Kona</td><<wbr>td></td><td></td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/P0467R2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0467R2</a>">P0467R2</a></td><td><wbr>LWG</td><td>Iterator Concerns for Parallel Algorithms</td><td>Kona</td><<wbr>td></td><td></td></tr><br>
-       <tr><td><a href="<a href="https://wg21.link/P0492R2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0492R2</a>">P0492R2</a></td><td><wbr>LWG</td><td>Proposed Resolution of C++17 National Body Comments for Filesystems</td><td>Kona</td><<wbr>td></td><td></td></tr><br>
+       <tr><td><a href="<a href="https://wg21.link/P0492R2" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0492R2</a>">P0492R2</a></td><td><wbr>LWG</td><td>Proposed Resolution of C++17 National Body Comments for Filesystems</td><td>Kona</td><<wbr>td>Complete</td><td>7.0</td></<wbr>tr><br>
        <tr><td><a href="<a href="https://wg21.link/P0518R1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0518R1</a>">P0518R1</a></td><td><wbr>LWG</td><td>Allowing copies as arguments to function objects given to parallel algorithms in response to CH11</td><td>Kona</td><td></<wbr>td><td></td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/P0523R1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0523R1</a>">P0523R1</a></td><td><wbr>LWG</td><td>Wording for CH 10: Complexity of parallel algorithms</td><td>Kona</td><<wbr>td></td><td></td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/P0548R1" rel="noreferrer" target="_blank">https://wg21.link/<wbr>P0548R1</a>">P0548R1</a></td><td><wbr>LWG</td><td>common_type and duration</td><td>Kona</td><td><wbr>Complete</td><td>5.0</td></tr><br>
<br>
Modified: libcxx/trunk/www/cxx2a_status.<wbr>html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx2a_status.html?rev=329028&r1=329027&r2=329028&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxx/trunk/www/<wbr>cxx2a_status.html?rev=329028&<wbr>r1=329027&r2=329028&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/www/cxx2a_status.<wbr>html (original)<br>
+++ libcxx/trunk/www/cxx2a_status.<wbr>html Mon Apr  2 16:03:41 2018<br>
@@ -164,7 +164,7 @@<br>
        <tr><td><a href="<a href="https://wg21.link/LWG3015" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3015</a>">3015</a></td><td><tt><wbr>copy_options::<i>unspecified</<wbr>i></tt> underspecified</td><td><wbr>Jacksonville</td><td><i><wbr>Nothing to do</i></td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/LWG3017" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3017</a>">3017</a></td><td><tt><wbr>list splice</tt> functions should use <tt>addressof</tt></td><td><wbr>Jacksonville</td><td></td></<wbr>tr><br>
        <tr><td><a href="<a href="https://wg21.link/LWG3020" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3020</a>">3020</a></td><td>[<wbr>networking.ts] Remove spurious nested <tt>value_type</tt> buffer sequence requirement</td><td><wbr>Jacksonville</td><td></td></<wbr>tr><br>
-       <tr><td><a href="<a href="https://wg21.link/LWG3026" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3026</a>">3026</a></td><td><tt><wbr>filesystem::weakly_canonical</<wbr>tt> still defined in terms of <tt>canonical(p, base)</tt></td><td><wbr>Jacksonville</td><td></td></<wbr>tr><br>
+       <tr><td><a href="<a href="https://wg21.link/LWG3026" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3026</a>">3026</a></td><td><tt><wbr>filesystem::weakly_canonical</<wbr>tt> still defined in terms of <tt>canonical(p, base)</tt></td><td><wbr>Jacksonville</td><td>Complete<<wbr>/td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/LWG3030" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3030</a>">3030</a></td><td>Who shall meet the requirements of <tt>try_lock</tt>?</td><td><wbr>Jacksonville</td><td><i><wbr>Nothing to do</i></td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/LWG3034" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3034</a>">3034</a></td><td><wbr>P0767R1 breaks previously-standard-layout types</td><td>Jacksonville</<wbr>td><td>Complete</td></tr><br>
        <tr><td><a href="<a href="https://wg21.link/LWG3035" rel="noreferrer" target="_blank">https://wg21.link/<wbr>LWG3035</a>">3035</a></td><td><tt><wbr>std::allocator</tt>'s constructors should be <tt>constexpr</tt></td><td><wbr>Jacksonville</td><td>Complete<<wbr>/td></tr><br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>