libstdc++: Implement LWG 3070 in path::lexically_relative
authorJonathan Wakely <jwakely@redhat.com>
Fri, 15 Nov 2019 19:58:15 +0000 (19:58 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 15 Nov 2019 19:58:15 +0000 (19:58 +0000)
* src/c++17/fs_path.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
(is_disk_designator): New helper function.
(path::_Parser::root_path()): Use is_disk_designator.
(path::lexically_relative(const path&)): Implement resolution of
LWG 3070.
* testsuite/27_io/filesystem/path/generation/relative.cc: Check with
path components that look like a root-name.

From-SVN: r278313

libstdc++-v3/ChangeLog
libstdc++-v3/src/c++17/fs_path.cc
libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc

index 53f3b2961c867d0de088c0c0329949cbd08b9b3c..e6094bd7a729713fa50e693d210322f37f277314 100644 (file)
@@ -1,5 +1,13 @@
 2019-11-15  Jonathan Wakely  <jwakely@redhat.com>
 
+       * src/c++17/fs_path.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
+       (is_disk_designator): New helper function.
+       (path::_Parser::root_path()): Use is_disk_designator.
+       (path::lexically_relative(const path&)): Implement resolution of
+       LWG 3070.
+       * testsuite/27_io/filesystem/path/generation/relative.cc: Check with
+       path components that look like a root-name.
+
        * doc/doxygen/user.cfg.in: Add <stop_token>.
        * include/precompiled/stdc++.h: Likewise.
        * include/std/stop_token: Fix definition of std::nostopstate.
index 14842452354e089febbe699e34badfaacb333fdb..5fba971fef670b4154e8adb447efccacc1d6c51e 100644 (file)
@@ -47,6 +47,13 @@ static inline bool is_dir_sep(path::value_type ch)
 #endif
 }
 
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+static inline bool is_disk_designator(std::wstring_view s)
+{
+  return s.length() == 2 && s[1] == L':';
+}
+#endif
+
 struct path::_Parser
 {
   using string_view_type = std::basic_string_view<value_type>;
@@ -117,7 +124,7 @@ struct path::_Parser
          ++pos;
       }
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-    else if (len > 1 && input[1] == L':')
+    else if (is_disk_designator(input.substr(0, 2)))
       {
        // got disk designator
        root.first.str = input.substr(0, 2);
@@ -1747,6 +1754,19 @@ path::lexically_relative(const path& base) const
   if (!has_root_directory() && base.has_root_directory())
     return ret;
   auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3070. path::lexically_relative causes surprising results if a filename
+  // can also be a root-name
+  if (!empty())
+    for (auto& p : _M_cmpts)
+      if (p._M_type() == _Type::_Filename && is_disk_designator(p.native()))
+       return ret;
+  if (!base.empty())
+    for (auto i = b, end = base.end(); i != end; ++i)
+      if (i->_M_type() == _Type::_Filename && is_disk_designator(i->native()))
+       return ret;
+#endif
   if (a == end() && b == base.end())
     ret = ".";
   else
index dde08d46f2cbb8940b53a54191ef0101dc84e06b..b2ac27293b23e652412135ea8587923273c50ad3 100644 (file)
@@ -77,10 +77,26 @@ test03()
   compare_paths( path("/dir/.").lexically_relative("/dir/."), "." );
 }
 
+void
+test04()
+{
+#if defined(__MING32__) || defined(__MINGW64__)
+  // DR 3070
+  compare_paths(path("c:/f:o/bar").lexically_relative("c:/f:o/bar"), ".");
+  compare_paths(path("c:/foo/bar").lexically_relative("c:/foo/b:r"), "..\\bar");
+  compare_paths(path("c:/foo/b:r").lexically_relative("c:/foo/bar"), "..\\b:r");
+  compare_paths(path("c:/foo/b:").lexically_relative("c:/foo/b:"), "");
+  compare_paths(path("c:/foo/bar").lexically_relative("c:/foo/b:"), "");
+  compare_paths(path("c:/f:/bar").lexically_relative("c:/foo/bar"), "");
+  compare_paths(path("foo/bar").lexically_relative("foo/b:/bar"), "");
+#endif
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }