diff --git a/src/verbose_air.zig b/src/verbose_air.zig index 073837ca37..c0b540443b 100644 --- a/src/verbose_air.zig +++ b/src/verbose_air.zig @@ -142,11 +142,13 @@ const AirComparer = struct { export fn zig_compare_air( src_path_ptr: [*:0]const u8, + module_root_ptr: ?[*:0]const u8, c_funcs_raw: ?*const anyopaque, c_func_count: u32, ) CompareResult { return zigCompareAirImpl( std.mem.span(src_path_ptr), + if (module_root_ptr) |p| std.mem.span(p) else null, @ptrCast(@alignCast(c_funcs_raw)), c_func_count, ) catch |err| { @@ -166,6 +168,7 @@ fn errResult(msg: []const u8) CompareResult { fn zigCompareAirImpl( src_path: []const u8, + module_root_opt: ?[]const u8, c_funcs: ?[*]const CSemaFuncAir, c_func_count: u32, ) !CompareResult { @@ -210,14 +213,22 @@ fn zigCompareAirImpl( // This avoids root mismatches in isNested checks, and also avoids resolving // symlinks — the caller may use a directory symlink to keep the module root // outside lib/std/ while preserving relative import resolution. - const src_dir = std.fs.path.dirname(src_path) orelse "."; - const src_basename = std.fs.path.basename(src_path); + const src_dir = module_root_opt orelse (std.fs.path.dirname(src_path) orelse "."); + const root_src_path = if (module_root_opt) |mr| blk: { + // src_path is "module_root/relative/path.zig" — strip module_root prefix + if (std.mem.startsWith(u8, src_path, mr)) { + var rest = src_path[mr.len..]; + if (rest.len > 0 and rest[0] == std.fs.path.sep) rest = rest[1..]; + break :blk rest; + } + break :blk std.fs.path.basename(src_path); // fallback + } else std.fs.path.basename(src_path); const root_path = try Compilation.Path.fromUnresolved(arena, dirs, &.{src_dir}); const root_mod = try Package.Module.create(arena, .{ .paths = .{ .root = root_path, - .root_src_path = src_basename, + .root_src_path = root_src_path, }, .fully_qualified_name = "root", .cc_argv = &.{}, diff --git a/stage0/dump.h b/stage0/dump.h index e0b17caee7..5ecee38c52 100644 --- a/stage0/dump.h +++ b/stage0/dump.h @@ -11,7 +11,7 @@ typedef struct { } AirCompareResult; // c_funcs: pointer to SemaFuncAir array (from sema.h). Passed as void* to avoid header dep. -extern AirCompareResult zig_compare_air(const char* src_path, const void* c_funcs, uint32_t c_func_count); +extern AirCompareResult zig_compare_air(const char* src_path, const char* module_root, const void* c_funcs, uint32_t c_func_count); extern void zig_compare_result_free(AirCompareResult* result); #endif diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig index a18608fcde..dd6a23eb28 100644 --- a/stage0/sema_test.zig +++ b/stage0/sema_test.zig @@ -12,7 +12,7 @@ const AirCompareResult = extern struct { matched_count: u32, error_msg: ?[*:0]u8, }; -extern fn zig_compare_air([*:0]const u8, ?*const anyopaque, u32) AirCompareResult; +extern fn zig_compare_air([*:0]const u8, ?[*:0]const u8, ?*const anyopaque, u32) AirCompareResult; extern fn zig_compare_result_free(*AirCompareResult) void; // Helper to convert C #define integer constants (c_int) to u32 for comparison @@ -245,7 +245,7 @@ fn semaAirRawCheck(source: [:0]const u8) !void { } defer std.fs.cwd().deleteFile(tmp_path) catch {}; - var cmp_result = zig_compare_air(tmp_path, @ptrCast(result.c_func_air_list.items), result.c_func_air_list.len); + var cmp_result = zig_compare_air(tmp_path, null, @ptrCast(result.c_func_air_list.items), result.c_func_air_list.len); defer zig_compare_result_free(&cmp_result); if (cmp_result.error_msg) |e| { std.debug.print("zig_compare_air error: {s}\n", .{std.mem.span(e)}); diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig index c0b04e0229..fe4052237e 100644 --- a/stage0/stages_test.zig +++ b/stage0/stages_test.zig @@ -13,7 +13,7 @@ const AirCompareResult = extern struct { matched_count: u32, error_msg: ?[*:0]u8, }; -extern fn zig_compare_air([*:0]const u8, ?*const anyopaque, u32) AirCompareResult; +extern fn zig_compare_air([*:0]const u8, ?[*:0]const u8, ?*const anyopaque, u32) AirCompareResult; extern fn zig_compare_result_free(*AirCompareResult) void; test "stages: corpus" { @@ -71,22 +71,29 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8) var c_func_air_list = sc.semaAnalyze(&c_sema); defer sc.semaFuncAirListDeinit(&c_func_air_list); - // Symlink the original file's directory to avoid module path conflicts - // (source files inside lib/std/ conflict with the 'std' module) - // while preserving relative import resolution for subdirectory imports. + // Symlink to the repo root so all relative imports resolve within + // the module root, while keeping logical paths under .zig-cache/tmp/ + // to avoid 'std' module conflicts with lib/std/. const this_dir = comptime std.fs.path.dirname(@src().file) orelse "."; - const original_dir = comptime std.fs.path.dirname(this_dir ++ "/" ++ path) orelse "."; const symlink_path = ".zig-cache/tmp/zig0_test"; - const abs_original_dir = std.fs.cwd().realpathAlloc(gpa, original_dir) catch return error.ResolvePath; - defer gpa.free(abs_original_dir); + // All corpus paths start with "../"; strip to get repo-relative path. + const repo_relative = comptime blk: { + if (!std.mem.startsWith(u8, path, "../")) + @compileError("corpus path must start with '../'"); + break :blk path["../".len..]; + }; + + const abs_repo_root = std.fs.cwd().realpathAlloc(gpa, comptime this_dir ++ "/..") catch return error.ResolvePath; + defer gpa.free(abs_repo_root); std.fs.cwd().deleteFile(symlink_path) catch {}; - std.fs.cwd().symLink(abs_original_dir, symlink_path, .{ .is_directory = true }) catch return error.SymlinkCreate; + std.fs.cwd().symLink(abs_repo_root, symlink_path, .{ .is_directory = true }) catch return error.SymlinkCreate; defer std.fs.cwd().deleteFile(symlink_path) catch {}; - const test_src: [:0]const u8 = symlink_path ++ "/" ++ comptime std.fs.path.basename(path); - var cmp_result = zig_compare_air(test_src.ptr, @ptrCast(c_func_air_list.items), c_func_air_list.len); + const test_src: [:0]const u8 = symlink_path ++ "/" ++ repo_relative; + const module_root: [:0]const u8 = symlink_path; + var cmp_result = zig_compare_air(test_src.ptr, module_root.ptr, @ptrCast(c_func_air_list.items), c_func_air_list.len); defer zig_compare_result_free(&cmp_result); if (cmp_result.error_msg) |e| { std.debug.print("zig_compare_air error: {s}\n", .{std.mem.span(e)}); @@ -104,7 +111,7 @@ const last_successful_corpus = "../lib/std/crypto/codecs.zig"; // find ../{lib,src} -name '*.zig' | xargs -n1 stat -c "%s %n" | sort -n | awk '{printf " \""$2"\", // "$1"\n"}' const corpus_files = .{ "../lib/std/crypto/codecs.zig", // 165 - //"../lib/std/os/uefi/tables/table_header.zig", // 214 + "../lib/std/os/uefi/tables/table_header.zig", // 214 //"../lib/std/zig/llvm.zig", // 247 //"../lib/compiler_rt/neghf2.zig", // 265 //"../lib/compiler_rt/negxf2.zig", // 265