Files
zig/stage0/stages_test.zig
Motiejus 6b8dc8dd9f stage0: prepare for IP gap closure (return_integer.zig)
- Enable module_root for sema unit tests in stages_test.zig, matching
  the Zig compiler which always creates std even with std_mod=null.
  The first 5 tests still pass since they only use pre-interned refs.

- Add analyzeMemoizedStateC infrastructure for resolving std.builtin
  BuiltinDecl entries (ExportOptions, CallingConvention, Type, etc.).
  Not yet triggered — the trigger path requires matching the Zig
  compiler's exact module loading order.

- Add --module-root flag to zig0 CLI for debugging IP entry comparison
  between the Zig compiler and C sema.

- Fix cppcheck warning: remove redundant !fi.is_inline check (already
  guarded by early return above).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 17:22:17 +00:00

105 lines
4.3 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
const Ast = std.zig.Ast;
const AstGen = std.zig.AstGen;
const parser_test = @import("parser_test.zig");
const astgen_test = @import("astgen_test.zig");
const sema_test = @import("sema_test.zig");
const c = parser_test.c;
const sc = sema_test.c;
const corpus = @import("corpus.zig");
test "stages: corpus" {
@setEvalBranchQuota(corpus.files.len * 100);
const gpa = std.testing.allocator;
inline for (corpus.files[0..corpus.num_passing]) |path| {
stagesCheck(gpa, path, @embedFile("../" ++ path)) catch {
std.debug.print("FAIL: {s}\n", .{path});
return error.TestFailed;
};
}
}
fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8) !void {
// Parse once with C parser
var c_ast = c.astParse(source.ptr, @intCast(source.len));
defer c.astDeinit(&c_ast);
// Convert C AST to Zig AST once
var tree = try parser_test.zigAst(gpa, c_ast);
defer tree.deinit(gpa);
// Stage 1: Parser — compare C and Zig ASTs, check canonical rendering
if (!std.debug.inValgrind()) {
var zig_tree = try Ast.parse(gpa, source, .zig);
defer zig_tree.deinit(gpa);
try parser_test.expectAstConsistent(tree, zig_tree, source);
}
if (tree.errors.len == 0) {
const formatted = try tree.renderAlloc(gpa);
defer gpa.free(formatted);
try std.testing.expectEqualStrings(source, formatted);
}
// Stage 2: AstGen — compare C and Zig ZIR
var ref_zir = try AstGen.generate(gpa, tree);
defer ref_zir.deinit(gpa);
var c_zir = c.astGen(&c_ast);
defer c.zirDeinit(&c_zir);
if (c_zir.has_compile_errors) {
std.debug.print("C port returned compile errors (inst_len={d})\n", .{c_zir.inst_len});
return error.TestUnexpectedResult;
}
try astgen_test.expectEqualZir(gpa, ref_zir, c_zir);
// Stage 3: Sema — compare C sema vs pre-computed AIR
{
const this_dir = comptime std.fs.path.dirname(@src().file) orelse ".";
const abs_repo_root = std.fs.cwd().realpathAlloc(gpa, comptime this_dir ++ "/..") catch return error.ResolvePath;
defer gpa.free(abs_repo_root);
const repo_dir = comptime std.fs.path.dirname(path) orelse ".";
var source_dir_buf: [std.fs.max_path_bytes:0]u8 = undefined;
const source_dir_path = std.fmt.bufPrintZ(&source_dir_buf, "{s}/{s}", .{ abs_repo_root, repo_dir }) catch unreachable;
var module_root_buf: [std.fs.max_path_bytes:0]u8 = undefined;
const module_root_path = std.fmt.bufPrintZ(&module_root_buf, "{s}", .{abs_repo_root}) catch unreachable;
var c_ip = sc.ipInit();
defer sc.ipDeinit(&c_ip);
var c_sema: sc.Sema = undefined;
sc.semaInit(&c_sema, &c_ip, @bitCast(c_zir));
defer sc.semaDeinit(&c_sema);
// Pre-generated AIR uses ReleaseSmall (strip=true), so match it.
c_sema.strip = true;
// Set source_dir, module_root, root_fqn based on path prefix.
if (comptime std.mem.startsWith(u8, path, "stage0/")) {
// Sema unit tests: set module_root to enable std/start/builtin
// loading, matching the Zig compiler which always creates std
// even with std_mod=null (Compilation.zig line 2196).
c_sema.source_dir = source_dir_path.ptr;
c_sema.module_root = module_root_path.ptr;
c_sema.root_fqn = comptime sema_test.pathStem(path);
} else if (comptime std.mem.startsWith(u8, path, "lib/std/")) {
c_sema.source_dir = source_dir_path.ptr;
c_sema.module_root = module_root_path.ptr;
c_sema.root_fqn = "std";
c_sema.module_prefix = sema_test.pathToModulePrefix(path);
} else {
c_sema.source_dir = source_dir_path.ptr;
c_sema.module_root = module_root_path.ptr;
c_sema.root_fqn = comptime sema_test.pathStem(path);
}
var c_func_air_list = sc.semaAnalyze(&c_sema);
defer sc.semaFuncAirListDeinit(&c_func_air_list);
const air_data = @import("air_data").getData(path);
const precomputed = try sema_test.parsePrecomputedAir(air_data);
defer sema_test.freePrecomputedAir(precomputed);
try sema_test.airComparePrecomputed(precomputed, c_func_air_list);
}
}