authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-08-13 21:44:18-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2026-08-14 12:25:13+02:00
log7b890ff9789caf010639277168d5f5852a9d852e
treea7f36a8e130d9bb5b0a285b8dc7b48a369b9d058
parent63cfe88f0c011895fdd573703ad6715ec91e3231

Fix Compilation.Path checks when one path is a root path

Previously, it was assumed that the byte after the cwd/outer path had to be a path separator, but that's not true when the cwd/outer path is a root with no components (e.g. `/` or `C:\`) Fixes #32005

1 files changed, 14 insertions(+), 4 deletions(-)

src/Compilation.zig+14-4
...@@ -484,8 +484,13 @@ pub const Path = struct {...@@ -484,8 +484,13 @@ pub const Path = struct {
484 assert(fs.path.isAbsolute(sub_path));484 assert(fs.path.isAbsolute(sub_path));
485 if (!std.mem.startsWith(u8, sub_path, cwd_path)) return sub_path;485 if (!std.mem.startsWith(u8, sub_path, cwd_path)) return sub_path;
486 if (sub_path.len == cwd_path.len) return "."; // the strings are equal486 if (sub_path.len == cwd_path.len) return "."; // the strings are equal
487 if (sub_path[cwd_path.len] != fs.path.sep) return sub_path; // last component before cwd differs487 const path_sep_index = path_sep_index: {
488 return sub_path[cwd_path.len + 1 ..]; // remove '/path/to/cwd/' prefix488 // cwd is just a root, e.g. / or C:\
489 if (cwd_path[cwd_path.len - 1] == fs.path.sep) break :path_sep_index cwd_path.len - 1;
490 if (sub_path[cwd_path.len] != fs.path.sep) return sub_path; // last component before cwd differs
491 break :path_sep_index cwd_path.len;
492 };
493 return sub_path[path_sep_index + 1 ..]; // remove '/path/to/cwd/' prefix
489 }494 }
490495
491 /// From an unresolved path (which can be made of multiple not-yet-joined strings), construct a496 /// From an unresolved path (which can be made of multiple not-yet-joined strings), construct a
...@@ -672,8 +677,13 @@ pub const Path = struct {...@@ -672,8 +677,13 @@ pub const Path = struct {
672 if (!mem.startsWith(u8, inner.sub_path, outer.sub_path)) return .no;677 if (!mem.startsWith(u8, inner.sub_path, outer.sub_path)) return .no;
673 if (inner.sub_path.len == outer.sub_path.len) return .no;678 if (inner.sub_path.len == outer.sub_path.len) return .no;
674 if (outer.sub_path.len == 0) return .{ .yes = inner.sub_path };679 if (outer.sub_path.len == 0) return .{ .yes = inner.sub_path };
675 if (inner.sub_path[outer.sub_path.len] != fs.path.sep) return .no;680 const path_sep_index = path_sep_index: {
676 return .{ .yes = inner.sub_path[outer.sub_path.len + 1 ..] };681 // outer is just a root, e.g. / or C:\
682 if (outer.sub_path[outer.sub_path.len - 1] == fs.path.sep) break :path_sep_index outer.sub_path.len - 1;
683 if (inner.sub_path[outer.sub_path.len] != fs.path.sep) return .no;
684 break :path_sep_index outer.sub_path.len;
685 };
686 return .{ .yes = inner.sub_path[path_sep_index + 1 ..] };
677 }687 }
678688
679 /// Returns whether this `Path` is illegal to have as a user-imported `Zcu.File` (including689 /// Returns whether this `Path` is illegal to have as a user-imported `Zcu.File` (including