[libcxx-commits] [libcxx] aa427b1 - [libc++] Fix backslash as root dir breaks lexically_relative, lexically_proximate and hash_value on Windows (#99780)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Aug 16 06:26:42 PDT 2024
Author: RichardLuo
Date: 2024-08-16T09:26:38-04:00
New Revision: aa427b1aae445ed46d9f60c5e2eaac61bdf76be3
URL: https://github.com/llvm/llvm-project/commit/aa427b1aae445ed46d9f60c5e2eaac61bdf76be3
DIFF: https://github.com/llvm/llvm-project/commit/aa427b1aae445ed46d9f60c5e2eaac61bdf76be3.diff
LOG: [libc++] Fix backslash as root dir breaks lexically_relative, lexically_proximate and hash_value on Windows (#99780)
Various functions like hash_value, lexically_proximate and lexically_relative
would incorrectly handle backslashes in the root directory on Windows, causing
behavior that is inconsistent with the equality comparison for a path.
Added:
Modified:
libcxx/src/filesystem/path.cpp
libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/src/filesystem/path.cpp b/libcxx/src/filesystem/path.cpp
index b2019521377ede..58742442bae6b7 100644
--- a/libcxx/src/filesystem/path.cpp
+++ b/libcxx/src/filesystem/path.cpp
@@ -267,7 +267,7 @@ path path::lexically_relative(const path& base) const {
// Find the first mismatching element
auto PP = PathParser::CreateBegin(__pn_);
auto PPBase = PathParser::CreateBegin(base.__pn_);
- while (PP && PPBase && PP.State_ == PPBase.State_ && *PP == *PPBase) {
+ while (PP && PPBase && PP.State_ == PPBase.State_ && (*PP == *PPBase || PP.inRootDir())) {
++PP;
++PPBase;
}
@@ -368,7 +368,8 @@ size_t hash_value(const path& __p) noexcept {
size_t hash_value = 0;
hash<string_view_t> hasher;
while (PP) {
- hash_value = __hash_combine(hash_value, hasher(*PP));
+ string_view_t Part = PP.inRootDir() ? PATHSTR("/") : *PP;
+ hash_value = __hash_combine(hash_value, hasher(Part));
++PP;
}
return hash_value;
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
index 99f55d3b17f1b0..3bebf38a2a7c34 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp
@@ -47,13 +47,20 @@ struct PathCompareTest {
int expect;
};
-#define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
-#define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
-#define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
-#define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
-const PathCompareTest CompareTestCases[] =
-{
- {"", "", 0},
+#define LONGA \
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
+ "AAAAAAAA"
+#define LONGB \
+ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" \
+ "BBBBBBBB"
+#define LONGC \
+ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" \
+ "CCCCCCCC"
+#define LONGD \
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" \
+ "DDDDDDDD"
+const PathCompareTest CompareTestCases[] = {
+ {"", "", 0},
{"a", "", 1},
{"", "a", -1},
{"a/b/c", "a/b/c", 0},
@@ -62,14 +69,19 @@ const PathCompareTest CompareTestCases[] =
{"a/b", "a/b/c", -1},
{"a/b/c", "a/b", 1},
{"a/b/", "a/b/.", -1},
- {"a/b/", "a/b", 1},
+ {"a/b/", "a/b", 1},
{"a/b//////", "a/b/////.", -1},
{"a/.././b", "a///..//.////b", 0},
{"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators
- {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory
- {"/foo/bar/", "/foo/bar", 1}, // trailing separator
+ {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory
+ {"/foo/bar/", "/foo/bar", 1}, // trailing separator
{"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0.
- {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.
+ {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.
+#ifdef _WIN32
+ {"C:/a", "C:\\a", 0},
+#else
+ {"C:/a", "C:\\a", -1},
+#endif
{("//" LONGA "////" LONGB "/" LONGC "///" LONGD), ("//" LONGA "/" LONGB "/" LONGC "/" LONGD), 0},
{(LONGA "/" LONGB "/" LONGC), (LONGA "/" LONGB "/" LONGB), 1}
@@ -79,23 +91,19 @@ const PathCompareTest CompareTestCases[] =
#undef LONGC
#undef LONGD
-static inline int normalize_ret(int ret)
-{
- return ret < 0 ? -1 : (ret > 0 ? 1 : 0);
-}
+static inline int normalize_ret(int ret) { return ret < 0 ? -1 : (ret > 0 ? 1 : 0); }
-void test_compare_basic()
-{
+void test_compare_basic() {
using namespace fs;
- for (auto const & TC : CompareTestCases) {
+ for (auto const& TC : CompareTestCases) {
const path p1(TC.LHS);
const path p2(TC.RHS);
std::string RHS(TC.RHS);
const path::string_type R(RHS.begin(), RHS.end());
const std::basic_string_view<path::value_type> RV(R);
- const path::value_type *Ptr = R.c_str();
- const int E = TC.expect;
- { // compare(...) functions
+ const path::value_type* Ptr = R.c_str();
+ const int E = TC.expect;
+ { // compare(...) functions
DisableAllocationGuard g; // none of these operations should allocate
// check runtime results
@@ -113,7 +121,7 @@ void test_compare_basic()
// check signatures
ASSERT_NOEXCEPT(p1.compare(p2));
}
- { // comparison operators
+ { // comparison operators
DisableAllocationGuard g; // none of these operations should allocate
// check signatures
@@ -180,14 +188,14 @@ void test_compare_elements() {
auto BuildPath = [](std::vector<std::string> const& Elems) {
fs::path p;
- for (auto &E : Elems)
+ for (auto& E : Elems)
p /= E;
return p;
};
- for (auto &TC : TestCases) {
- fs::path LHS = BuildPath(TC.LHSElements);
- fs::path RHS = BuildPath(TC.RHSElements);
+ for (auto& TC : TestCases) {
+ fs::path LHS = BuildPath(TC.LHSElements);
+ fs::path RHS = BuildPath(TC.RHSElements);
const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements);
assert(ExpectCmp == TC.Expect);
const int GotCmp = normalize_ret(LHS.compare(RHS));
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
index 42fa813ada4a5c..06954fe876e557 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.gen/lexically_relative_and_proximate.pass.cpp
@@ -41,9 +41,11 @@ int main(int, char**) {
#ifdef _WIN32
{"//net/", "//net", ""},
{"//net", "//net/", ""},
+ {"C:\\a\\b", "C:/a", "b"},
#else
{"//net/", "//net", "."},
{"//net", "//net/", "."},
+ {"C:\\a\\b", "C:/a", "../../C:\\a\\b"},
#endif
{"//base", "a", ""},
{"a", "a", "."},
More information about the libcxx-commits
mailing list