- 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>
105 lines
4.3 KiB
Zig
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);
|
|
}
|
|
}
|