add ZIR compare output test case to test suite
This commit is contained in:
parent
b23a87953a
commit
2bae942800
@ -44,7 +44,7 @@ pub fn build(b: *Builder) !void {
|
|||||||
try findAndReadConfigH(b);
|
try findAndReadConfigH(b);
|
||||||
|
|
||||||
var test_stage2 = b.addTest("src-self-hosted/test.zig");
|
var test_stage2 = b.addTest("src-self-hosted/test.zig");
|
||||||
test_stage2.setBuildMode(builtin.Mode.Debug);
|
test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness
|
||||||
test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");
|
test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");
|
||||||
|
|
||||||
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
|
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
|
||||||
@ -68,7 +68,6 @@ pub fn build(b: *Builder) !void {
|
|||||||
var ctx = parseConfigH(b, config_h_text);
|
var ctx = parseConfigH(b, config_h_text);
|
||||||
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
|
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
|
||||||
|
|
||||||
try configureStage2(b, test_stage2, ctx);
|
|
||||||
try configureStage2(b, exe, ctx);
|
try configureStage2(b, exe, ctx);
|
||||||
|
|
||||||
b.default_step.dependOn(&exe.step);
|
b.default_step.dependOn(&exe.step);
|
||||||
|
@ -46,6 +46,12 @@ pub const ChildProcess = struct {
|
|||||||
|
|
||||||
/// Set to change the current working directory when spawning the child process.
|
/// Set to change the current working directory when spawning the child process.
|
||||||
cwd: ?[]const u8,
|
cwd: ?[]const u8,
|
||||||
|
/// Set to change the current working directory when spawning the child process.
|
||||||
|
/// This is not yet implemented for Windows. See https://github.com/ziglang/zig/issues/5190
|
||||||
|
/// Once that is done, `cwd` will be deprecated in favor of this field.
|
||||||
|
/// The directory handle must be opened with the ability to be passed
|
||||||
|
/// to a child process (no `O_CLOEXEC` flag on POSIX).
|
||||||
|
cwd_dir: ?fs.Dir = null,
|
||||||
|
|
||||||
err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t,
|
err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t,
|
||||||
|
|
||||||
@ -183,6 +189,7 @@ pub const ChildProcess = struct {
|
|||||||
allocator: *mem.Allocator,
|
allocator: *mem.Allocator,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
cwd: ?[]const u8 = null,
|
cwd: ?[]const u8 = null,
|
||||||
|
cwd_dir: ?fs.Dir = null,
|
||||||
env_map: ?*const BufMap = null,
|
env_map: ?*const BufMap = null,
|
||||||
max_output_bytes: usize = 50 * 1024,
|
max_output_bytes: usize = 50 * 1024,
|
||||||
expand_arg0: Arg0Expand = .no_expand,
|
expand_arg0: Arg0Expand = .no_expand,
|
||||||
@ -194,6 +201,7 @@ pub const ChildProcess = struct {
|
|||||||
child.stdout_behavior = .Pipe;
|
child.stdout_behavior = .Pipe;
|
||||||
child.stderr_behavior = .Pipe;
|
child.stderr_behavior = .Pipe;
|
||||||
child.cwd = args.cwd;
|
child.cwd = args.cwd;
|
||||||
|
child.cwd_dir = args.cwd_dir;
|
||||||
child.env_map = args.env_map;
|
child.env_map = args.env_map;
|
||||||
child.expand_arg0 = args.expand_arg0;
|
child.expand_arg0 = args.expand_arg0;
|
||||||
|
|
||||||
@ -414,7 +422,9 @@ pub const ChildProcess = struct {
|
|||||||
os.close(stderr_pipe[1]);
|
os.close(stderr_pipe[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.cwd) |cwd| {
|
if (self.cwd_dir) |cwd| {
|
||||||
|
os.fchdir(cwd.fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
|
} else if (self.cwd) |cwd| {
|
||||||
os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
|
os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +606,8 @@ pub const Dir = struct {
|
|||||||
} else 0;
|
} else 0;
|
||||||
|
|
||||||
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
|
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
|
||||||
const os_flags = lock_flag | O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read)
|
const O_CLOEXEC: u32 = if (flags.share_with_child_process) 0 else os.O_CLOEXEC;
|
||||||
|
const os_flags = lock_flag | O_LARGEFILE | O_CLOEXEC | if (flags.write and flags.read)
|
||||||
@as(u32, os.O_RDWR)
|
@as(u32, os.O_RDWR)
|
||||||
else if (flags.write)
|
else if (flags.write)
|
||||||
@as(u32, os.O_WRONLY)
|
@as(u32, os.O_WRONLY)
|
||||||
@ -689,7 +690,8 @@ pub const Dir = struct {
|
|||||||
} else 0;
|
} else 0;
|
||||||
|
|
||||||
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
|
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
|
||||||
const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC |
|
const O_CLOEXEC: u32 = if (flags.share_with_child_process) 0 else os.O_CLOEXEC;
|
||||||
|
const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | O_CLOEXEC |
|
||||||
(if (flags.truncate) @as(u32, os.O_TRUNC) else 0) |
|
(if (flags.truncate) @as(u32, os.O_TRUNC) else 0) |
|
||||||
(if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) |
|
(if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) |
|
||||||
(if (flags.exclusive) @as(u32, os.O_EXCL) else 0);
|
(if (flags.exclusive) @as(u32, os.O_EXCL) else 0);
|
||||||
@ -787,6 +789,15 @@ pub const Dir = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function performs `makePath`, followed by `openDir`.
|
||||||
|
/// If supported by the OS, this operation is atomic. It is not atomic on
|
||||||
|
/// all operating systems.
|
||||||
|
pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir {
|
||||||
|
// TODO improve this implementation on Windows; we can avoid 1 call to NtClose
|
||||||
|
try self.makePath(sub_path);
|
||||||
|
return self.openDir(sub_path, open_dir_options);
|
||||||
|
}
|
||||||
|
|
||||||
/// Changes the current working directory to the open directory handle.
|
/// Changes the current working directory to the open directory handle.
|
||||||
/// This modifies global state and can have surprising effects in multi-
|
/// This modifies global state and can have surprising effects in multi-
|
||||||
/// threaded applications. Most applications and especially libraries should
|
/// threaded applications. Most applications and especially libraries should
|
||||||
@ -807,6 +818,11 @@ pub const Dir = struct {
|
|||||||
/// `true` means the opened directory can be scanned for the files and sub-directories
|
/// `true` means the opened directory can be scanned for the files and sub-directories
|
||||||
/// of the result. It means the `iterate` function can be called.
|
/// of the result. It means the `iterate` function can be called.
|
||||||
iterate: bool = false,
|
iterate: bool = false,
|
||||||
|
|
||||||
|
/// `true` means the opened directory can be passed to a child process.
|
||||||
|
/// `false` means the directory handle is considered to be closed when a child
|
||||||
|
/// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX.
|
||||||
|
share_with_child_process: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Opens a directory at the given path. The directory is a system resource that remains
|
/// Opens a directory at the given path. The directory is a system resource that remains
|
||||||
@ -832,9 +848,11 @@ pub const Dir = struct {
|
|||||||
return self.openDirW(&sub_path_w, args);
|
return self.openDirW(&sub_path_w, args);
|
||||||
} else if (!args.iterate) {
|
} else if (!args.iterate) {
|
||||||
const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0;
|
const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0;
|
||||||
return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH);
|
const O_CLOEXEC: u32 = if (args.share_with_child_process) 0 else os.O_CLOEXEC;
|
||||||
|
return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | O_CLOEXEC | O_PATH);
|
||||||
} else {
|
} else {
|
||||||
return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC);
|
const O_CLOEXEC: u32 = if (args.share_with_child_process) 0 else os.O_CLOEXEC;
|
||||||
|
return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | O_CLOEXEC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,11 @@ pub const File = struct {
|
|||||||
/// It allows the use of `noasync` when calling functions related to opening
|
/// It allows the use of `noasync` when calling functions related to opening
|
||||||
/// the file, reading, and writing.
|
/// the file, reading, and writing.
|
||||||
always_blocking: bool = false,
|
always_blocking: bool = false,
|
||||||
|
|
||||||
|
/// `true` means the opened directory can be passed to a child process.
|
||||||
|
/// `false` means the directory handle is considered to be closed when a child
|
||||||
|
/// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX.
|
||||||
|
share_with_child_process: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// TODO https://github.com/ziglang/zig/issues/3802
|
/// TODO https://github.com/ziglang/zig/issues/3802
|
||||||
@ -107,6 +112,11 @@ pub const File = struct {
|
|||||||
/// For POSIX systems this is the file system mode the file will
|
/// For POSIX systems this is the file system mode the file will
|
||||||
/// be created with.
|
/// be created with.
|
||||||
mode: Mode = default_mode,
|
mode: Mode = default_mode,
|
||||||
|
|
||||||
|
/// `true` means the opened directory can be passed to a child process.
|
||||||
|
/// `false` means the directory handle is considered to be closed when a child
|
||||||
|
/// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX.
|
||||||
|
share_with_child_process: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Upon success, the stream is in an uninitialized state. To continue using it,
|
/// Upon success, the stream is in an uninitialized state. To continue using it,
|
||||||
|
@ -193,6 +193,44 @@ pub fn expect(ok: bool) void {
|
|||||||
if (!ok) @panic("test failure");
|
if (!ok) @panic("test failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const TmpDir = struct {
|
||||||
|
dir: std.fs.Dir,
|
||||||
|
parent_dir: std.fs.Dir,
|
||||||
|
sub_path: [sub_path_len]u8,
|
||||||
|
|
||||||
|
const random_bytes_count = 12;
|
||||||
|
const sub_path_len = std.base64.Base64Encoder.calcSize(random_bytes_count);
|
||||||
|
|
||||||
|
pub fn cleanup(self: *TmpDir) void {
|
||||||
|
self.dir.close();
|
||||||
|
self.parent_dir.deleteTree(&self.sub_path) catch {};
|
||||||
|
self.parent_dir.close();
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {
|
||||||
|
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
|
||||||
|
std.crypto.randomBytes(&random_bytes) catch
|
||||||
|
@panic("unable to make tmp dir for testing: unable to get random bytes");
|
||||||
|
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
|
||||||
|
std.fs.base64_encoder.encode(&sub_path, &random_bytes);
|
||||||
|
|
||||||
|
var cache_dir = std.fs.cwd().makeOpenPath("zig-cache", .{}) catch
|
||||||
|
@panic("unable to make tmp dir for testing: unable to make and open zig-cache dir");
|
||||||
|
defer cache_dir.close();
|
||||||
|
var parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch
|
||||||
|
@panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir");
|
||||||
|
var dir = parent_dir.makeOpenPath(&sub_path, opts) catch
|
||||||
|
@panic("unable to make tmp dir for testing: unable to make and open the tmp dir");
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.dir = dir,
|
||||||
|
.parent_dir = parent_dir,
|
||||||
|
.sub_path = sub_path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test "expectEqual nested array" {
|
test "expectEqual nested array" {
|
||||||
const a = [2][2]f32{
|
const a = [2][2]f32{
|
||||||
[_]f32{ 1.0, 0.0 },
|
[_]f32{ 1.0, 0.0 },
|
||||||
|
@ -9,6 +9,23 @@ pub const ast = @import("zig/ast.zig");
|
|||||||
pub const system = @import("zig/system.zig");
|
pub const system = @import("zig/system.zig");
|
||||||
pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
|
pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
|
||||||
|
|
||||||
|
pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
|
||||||
|
var line: usize = 0;
|
||||||
|
var column: usize = 0;
|
||||||
|
for (source[0..byte_offset]) |byte| {
|
||||||
|
switch (byte) {
|
||||||
|
'\n' => {
|
||||||
|
line += 1;
|
||||||
|
column = 0;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
column += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .{ .line = line, .column = column };
|
||||||
|
}
|
||||||
|
|
||||||
test "" {
|
test "" {
|
||||||
@import("std").meta.refAllDecls(@This());
|
@import("std").meta.refAllDecls(@This());
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,12 @@ pub const NativeTargetInfo = struct {
|
|||||||
// over our own shared objects and find a dynamic linker.
|
// over our own shared objects and find a dynamic linker.
|
||||||
self_exe: {
|
self_exe: {
|
||||||
const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
|
const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
|
||||||
defer allocator.free(lib_paths);
|
defer {
|
||||||
|
for (lib_paths) |lib_path| {
|
||||||
|
allocator.free(lib_path);
|
||||||
|
}
|
||||||
|
allocator.free(lib_paths);
|
||||||
|
}
|
||||||
|
|
||||||
var found_ld_info: LdInfo = undefined;
|
var found_ld_info: LdInfo = undefined;
|
||||||
var found_ld_path: [:0]const u8 = undefined;
|
var found_ld_path: [:0]const u8 = undefined;
|
||||||
|
@ -4,10 +4,11 @@ const Allocator = std.mem.Allocator;
|
|||||||
const Value = @import("value.zig").Value;
|
const Value = @import("value.zig").Value;
|
||||||
const Type = @import("type.zig").Type;
|
const Type = @import("type.zig").Type;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const text = @import("ir/text.zig");
|
|
||||||
const BigInt = std.math.big.Int;
|
const BigInt = std.math.big.Int;
|
||||||
const Target = std.Target;
|
const Target = std.Target;
|
||||||
|
|
||||||
|
pub const text = @import("ir/text.zig");
|
||||||
|
|
||||||
/// These are in-memory, analyzed instructions. See `text.Inst` for the representation
|
/// These are in-memory, analyzed instructions. See `text.Inst` for the representation
|
||||||
/// of instructions that correspond to the ZIR text format.
|
/// of instructions that correspond to the ZIR text format.
|
||||||
/// This struct owns the `Value` and `Type` memory. When the struct is deallocated,
|
/// This struct owns the `Value` and `Type` memory. When the struct is deallocated,
|
||||||
@ -124,6 +125,10 @@ pub const Module = struct {
|
|||||||
pub fn deinit(self: *Module, allocator: *Allocator) void {
|
pub fn deinit(self: *Module, allocator: *Allocator) void {
|
||||||
allocator.free(self.exports);
|
allocator.free(self.exports);
|
||||||
allocator.free(self.errors);
|
allocator.free(self.errors);
|
||||||
|
for (self.fns) |f| {
|
||||||
|
allocator.free(f.body);
|
||||||
|
}
|
||||||
|
allocator.free(self.fns);
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
@ -795,7 +800,7 @@ pub fn main() anyerror!void {
|
|||||||
|
|
||||||
if (zir_module.errors.len != 0) {
|
if (zir_module.errors.len != 0) {
|
||||||
for (zir_module.errors) |err_msg| {
|
for (zir_module.errors) |err_msg| {
|
||||||
const loc = findLineColumn(source, err_msg.byte_offset);
|
const loc = std.zig.findLineColumn(source, err_msg.byte_offset);
|
||||||
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
||||||
}
|
}
|
||||||
if (debug_error_trace) return error.ParseFailure;
|
if (debug_error_trace) return error.ParseFailure;
|
||||||
@ -809,10 +814,10 @@ pub fn main() anyerror!void {
|
|||||||
|
|
||||||
if (analyzed_module.errors.len != 0) {
|
if (analyzed_module.errors.len != 0) {
|
||||||
for (analyzed_module.errors) |err_msg| {
|
for (analyzed_module.errors) |err_msg| {
|
||||||
const loc = findLineColumn(source, err_msg.byte_offset);
|
const loc = std.zig.findLineColumn(source, err_msg.byte_offset);
|
||||||
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
||||||
}
|
}
|
||||||
if (debug_error_trace) return error.ParseFailure;
|
if (debug_error_trace) return error.AnalysisFail;
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,30 +836,13 @@ pub fn main() anyerror!void {
|
|||||||
defer result.deinit(allocator);
|
defer result.deinit(allocator);
|
||||||
if (result.errors.len != 0) {
|
if (result.errors.len != 0) {
|
||||||
for (result.errors) |err_msg| {
|
for (result.errors) |err_msg| {
|
||||||
const loc = findLineColumn(source, err_msg.byte_offset);
|
const loc = std.zig.findLineColumn(source, err_msg.byte_offset);
|
||||||
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
|
||||||
}
|
}
|
||||||
if (debug_error_trace) return error.ParseFailure;
|
if (debug_error_trace) return error.LinkFailure;
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
|
|
||||||
var line: usize = 0;
|
|
||||||
var column: usize = 0;
|
|
||||||
for (source[0..byte_offset]) |byte| {
|
|
||||||
switch (byte) {
|
|
||||||
'\n' => {
|
|
||||||
line += 1;
|
|
||||||
column = 0;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
column += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .{ .line = line, .column = column };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performance optimization ideas:
|
// Performance optimization ideas:
|
||||||
// * when analyzing use a field in the Inst instead of HashMap to track corresponding instructions
|
// * when analyzing use a field in the Inst instead of HashMap to track corresponding instructions
|
||||||
|
@ -532,9 +532,10 @@ const Parser = struct {
|
|||||||
else => |byte| return self.failByte(byte),
|
else => |byte| return self.failByte(byte),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Inst.Fn.Body{
|
// Move the instructions to the arena
|
||||||
.instructions = body_context.instructions.toOwnedSlice(),
|
const instrs = try self.arena.allocator.alloc(*Inst, body_context.instructions.items.len);
|
||||||
};
|
mem.copy(*Inst, instrs, body_context.instructions.items);
|
||||||
|
return Inst.Fn.Body{ .instructions = instrs };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseStringLiteral(self: *Parser) ![]u8 {
|
fn parseStringLiteral(self: *Parser) ![]u8 {
|
||||||
@ -588,26 +589,27 @@ const Parser = struct {
|
|||||||
|
|
||||||
fn parseRoot(self: *Parser) !void {
|
fn parseRoot(self: *Parser) !void {
|
||||||
// The IR format is designed so that it can be tokenized and parsed at the same time.
|
// The IR format is designed so that it can be tokenized and parsed at the same time.
|
||||||
while (true) : (self.i += 1) switch (self.source[self.i]) {
|
while (true) {
|
||||||
';' => _ = try skipToAndOver(self, '\n'),
|
switch (self.source[self.i]) {
|
||||||
'@' => {
|
';' => _ = try skipToAndOver(self, '\n'),
|
||||||
self.i += 1;
|
'@' => {
|
||||||
const ident = try skipToAndOver(self, ' ');
|
self.i += 1;
|
||||||
skipSpace(self);
|
const ident = try skipToAndOver(self, ' ');
|
||||||
try requireEatBytes(self, "=");
|
skipSpace(self);
|
||||||
skipSpace(self);
|
try requireEatBytes(self, "=");
|
||||||
const inst = try parseInstruction(self, null);
|
skipSpace(self);
|
||||||
const ident_index = self.decls.items.len;
|
const inst = try parseInstruction(self, null);
|
||||||
if (try self.global_name_map.put(ident, ident_index)) |_| {
|
const ident_index = self.decls.items.len;
|
||||||
return self.fail("redefinition of identifier '{}'", .{ident});
|
if (try self.global_name_map.put(ident, ident_index)) |_| {
|
||||||
}
|
return self.fail("redefinition of identifier '{}'", .{ident});
|
||||||
try self.decls.append(inst);
|
}
|
||||||
continue;
|
try self.decls.append(inst);
|
||||||
},
|
},
|
||||||
' ', '\n' => continue,
|
' ', '\n' => self.i += 1,
|
||||||
0 => break,
|
0 => break,
|
||||||
else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}),
|
else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}),
|
||||||
};
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eatByte(self: *Parser, byte: u8) bool {
|
fn eatByte(self: *Parser, byte: u8) bool {
|
||||||
|
@ -1,237 +1,168 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const link = @import("link.zig");
|
||||||
const Target = std.Target;
|
const ir = @import("ir.zig");
|
||||||
const Compilation = @import("compilation.zig").Compilation;
|
const Allocator = std.mem.Allocator;
|
||||||
const introspect = @import("introspect.zig");
|
|
||||||
const testing = std.testing;
|
|
||||||
const errmsg = @import("errmsg.zig");
|
|
||||||
const ZigCompiler = @import("compilation.zig").ZigCompiler;
|
|
||||||
|
|
||||||
var ctx: TestContext = undefined;
|
var global_ctx: TestContext = undefined;
|
||||||
|
|
||||||
test "stage2" {
|
test "self-hosted" {
|
||||||
// TODO provide a way to run tests in evented I/O mode
|
try global_ctx.init();
|
||||||
if (!std.io.is_async) return error.SkipZigTest;
|
defer global_ctx.deinit();
|
||||||
|
|
||||||
// TODO https://github.com/ziglang/zig/issues/1364
|
try @import("stage2_tests").addCases(&global_ctx);
|
||||||
// TODO https://github.com/ziglang/zig/issues/3117
|
|
||||||
if (true) return error.SkipZigTest;
|
|
||||||
|
|
||||||
try ctx.init();
|
try global_ctx.run();
|
||||||
defer ctx.deinit();
|
|
||||||
|
|
||||||
try @import("stage2_tests").addCases(&ctx);
|
|
||||||
|
|
||||||
try ctx.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const file1 = "1.zig";
|
|
||||||
// TODO https://github.com/ziglang/zig/issues/3783
|
|
||||||
const allocator = std.heap.page_allocator;
|
|
||||||
|
|
||||||
pub const TestContext = struct {
|
pub const TestContext = struct {
|
||||||
zig_compiler: ZigCompiler,
|
zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase),
|
||||||
zig_lib_dir: []u8,
|
|
||||||
file_index: std.atomic.Int(usize),
|
|
||||||
group: std.event.Group(anyerror!void),
|
|
||||||
any_err: anyerror!void,
|
|
||||||
|
|
||||||
const tmp_dir_name = "stage2_test_tmp";
|
pub const ZIRCompareOutputCase = struct {
|
||||||
|
name: []const u8,
|
||||||
|
src: [:0]const u8,
|
||||||
|
expected_stdout: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn addZIRCompareOutput(
|
||||||
|
ctx: *TestContext,
|
||||||
|
name: []const u8,
|
||||||
|
src: [:0]const u8,
|
||||||
|
expected_stdout: []const u8,
|
||||||
|
) void {
|
||||||
|
ctx.zir_cmp_output_cases.append(.{
|
||||||
|
.name = name,
|
||||||
|
.src = src,
|
||||||
|
.expected_stdout = expected_stdout,
|
||||||
|
}) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
fn init(self: *TestContext) !void {
|
fn init(self: *TestContext) !void {
|
||||||
self.* = TestContext{
|
self.* = .{
|
||||||
.any_err = {},
|
.zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator),
|
||||||
.zig_compiler = undefined,
|
|
||||||
.zig_lib_dir = undefined,
|
|
||||||
.group = undefined,
|
|
||||||
.file_index = std.atomic.Int(usize).init(0),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.zig_compiler = try ZigCompiler.init(allocator);
|
|
||||||
errdefer self.zig_compiler.deinit();
|
|
||||||
|
|
||||||
self.group = std.event.Group(anyerror!void).init(allocator);
|
|
||||||
errdefer self.group.wait() catch {};
|
|
||||||
|
|
||||||
self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);
|
|
||||||
errdefer allocator.free(self.zig_lib_dir);
|
|
||||||
|
|
||||||
try std.fs.cwd().makePath(tmp_dir_name);
|
|
||||||
errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *TestContext) void {
|
fn deinit(self: *TestContext) void {
|
||||||
std.fs.cwd().deleteTree(tmp_dir_name) catch {};
|
self.zir_cmp_output_cases.deinit();
|
||||||
allocator.free(self.zig_lib_dir);
|
self.* = undefined;
|
||||||
self.zig_compiler.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self: *TestContext) !void {
|
fn run(self: *TestContext) !void {
|
||||||
std.event.Loop.startCpuBoundOperation();
|
var progress = std.Progress{};
|
||||||
self.any_err = self.group.wait();
|
const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len);
|
||||||
return self.any_err;
|
defer root_node.end();
|
||||||
|
|
||||||
|
const native_info = try std.zig.system.NativeTargetInfo.detect(std.heap.page_allocator, .{});
|
||||||
|
|
||||||
|
for (self.zir_cmp_output_cases.items) |case| {
|
||||||
|
std.testing.base_allocator_instance.reset();
|
||||||
|
try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target);
|
||||||
|
try std.testing.allocator_instance.validate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testCompileError(
|
fn runOneZIRCmpOutputCase(
|
||||||
self: *TestContext,
|
self: *TestContext,
|
||||||
source: []const u8,
|
allocator: *Allocator,
|
||||||
path: []const u8,
|
root_node: *std.Progress.Node,
|
||||||
line: usize,
|
case: ZIRCompareOutputCase,
|
||||||
column: usize,
|
target: std.Target,
|
||||||
msg: []const u8,
|
|
||||||
) !void {
|
) !void {
|
||||||
var file_index_buf: [20]u8 = undefined;
|
var tmp = std.testing.tmpDir(.{ .share_with_child_process = true });
|
||||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
|
defer tmp.cleanup();
|
||||||
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
|
|
||||||
|
|
||||||
if (std.fs.path.dirname(file1_path)) |dirname| {
|
var prg_node = root_node.start(case.name, 4);
|
||||||
try std.fs.cwd().makePath(dirname);
|
prg_node.activate();
|
||||||
|
defer prg_node.end();
|
||||||
|
|
||||||
|
var zir_module = x: {
|
||||||
|
var parse_node = prg_node.start("parse", null);
|
||||||
|
parse_node.activate();
|
||||||
|
defer parse_node.end();
|
||||||
|
|
||||||
|
break :x try ir.text.parse(allocator, case.src);
|
||||||
|
};
|
||||||
|
defer zir_module.deinit(allocator);
|
||||||
|
if (zir_module.errors.len != 0) {
|
||||||
|
debugPrintErrors(case.src, zir_module.errors);
|
||||||
|
return error.ParseFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
try std.fs.cwd().writeFile(file1_path, source);
|
var analyzed_module = x: {
|
||||||
|
var analyze_node = prg_node.start("analyze", null);
|
||||||
|
analyze_node.activate();
|
||||||
|
defer analyze_node.end();
|
||||||
|
|
||||||
var comp = try Compilation.create(
|
break :x try ir.analyze(allocator, zir_module, target);
|
||||||
&self.zig_compiler,
|
};
|
||||||
"test",
|
defer analyzed_module.deinit(allocator);
|
||||||
file1_path,
|
if (analyzed_module.errors.len != 0) {
|
||||||
.Native,
|
debugPrintErrors(case.src, analyzed_module.errors);
|
||||||
.Obj,
|
return error.ParseFailure;
|
||||||
.Debug,
|
|
||||||
true, // is_static
|
|
||||||
self.zig_lib_dir,
|
|
||||||
);
|
|
||||||
errdefer comp.destroy();
|
|
||||||
|
|
||||||
comp.start();
|
|
||||||
|
|
||||||
try self.group.call(getModuleEvent, comp, source, path, line, column, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn testCompareOutputLibC(
|
|
||||||
self: *TestContext,
|
|
||||||
source: []const u8,
|
|
||||||
expected_output: []const u8,
|
|
||||||
) !void {
|
|
||||||
var file_index_buf: [20]u8 = undefined;
|
|
||||||
const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
|
|
||||||
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
|
|
||||||
|
|
||||||
const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() });
|
|
||||||
if (std.fs.path.dirname(file1_path)) |dirname| {
|
|
||||||
try std.fs.cwd().makePath(dirname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try std.fs.cwd().writeFile(file1_path, source);
|
var link_result = x: {
|
||||||
|
var link_node = prg_node.start("link", null);
|
||||||
|
link_node.activate();
|
||||||
|
defer link_node.end();
|
||||||
|
|
||||||
var comp = try Compilation.create(
|
break :x try link.updateExecutableFilePath(
|
||||||
&self.zig_compiler,
|
allocator,
|
||||||
"test",
|
analyzed_module,
|
||||||
file1_path,
|
tmp.dir,
|
||||||
.Native,
|
"a.out",
|
||||||
.Exe,
|
);
|
||||||
.Debug,
|
};
|
||||||
false,
|
defer link_result.deinit(allocator);
|
||||||
self.zig_lib_dir,
|
if (link_result.errors.len != 0) {
|
||||||
);
|
debugPrintErrors(case.src, link_result.errors);
|
||||||
errdefer comp.destroy();
|
return error.LinkFailure;
|
||||||
|
|
||||||
_ = try comp.addLinkLib("c", true);
|
|
||||||
comp.link_out_file = output_file;
|
|
||||||
comp.start();
|
|
||||||
|
|
||||||
try self.group.call(getModuleEventSuccess, comp, output_file, expected_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn getModuleEventSuccess(
|
|
||||||
comp: *Compilation,
|
|
||||||
exe_file: []const u8,
|
|
||||||
expected_output: []const u8,
|
|
||||||
) anyerror!void {
|
|
||||||
defer comp.destroy();
|
|
||||||
const build_event = comp.events.get();
|
|
||||||
|
|
||||||
switch (build_event) {
|
|
||||||
.Ok => {
|
|
||||||
const argv = [_][]const u8{exe_file};
|
|
||||||
// TODO use event loop
|
|
||||||
const child = try std.ChildProcess.exec(.{
|
|
||||||
.allocator = allocator,
|
|
||||||
.argv = argv,
|
|
||||||
.max_output_bytes = 1024 * 1024,
|
|
||||||
});
|
|
||||||
switch (child.term) {
|
|
||||||
.Exited => |code| {
|
|
||||||
if (code != 0) {
|
|
||||||
return error.BadReturnCode;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
return error.Crashed;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (!mem.eql(u8, child.stdout, expected_output)) {
|
|
||||||
return error.OutputMismatch;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err,
|
|
||||||
.Fail => |msgs| {
|
|
||||||
const stderr = std.io.getStdErr();
|
|
||||||
try stderr.write("build incorrectly failed:\n");
|
|
||||||
for (msgs) |msg| {
|
|
||||||
defer msg.destroy();
|
|
||||||
try msg.printToFile(stderr, .Auto);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn getModuleEvent(
|
var exec_result = x: {
|
||||||
comp: *Compilation,
|
var exec_node = prg_node.start("execute", null);
|
||||||
source: []const u8,
|
exec_node.activate();
|
||||||
path: []const u8,
|
defer exec_node.end();
|
||||||
line: usize,
|
|
||||||
column: usize,
|
|
||||||
text: []const u8,
|
|
||||||
) anyerror!void {
|
|
||||||
defer comp.destroy();
|
|
||||||
const build_event = comp.events.get();
|
|
||||||
|
|
||||||
switch (build_event) {
|
break :x try std.ChildProcess.exec(.{
|
||||||
.Ok => {
|
.allocator = allocator,
|
||||||
@panic("build incorrectly succeeded");
|
.argv = &[_][]const u8{"./a.out"},
|
||||||
},
|
.cwd_dir = tmp.dir,
|
||||||
.Error => |err| {
|
});
|
||||||
@panic("build incorrectly failed");
|
};
|
||||||
},
|
defer allocator.free(exec_result.stdout);
|
||||||
.Fail => |msgs| {
|
defer allocator.free(exec_result.stderr);
|
||||||
testing.expect(msgs.len != 0);
|
switch (exec_result.term) {
|
||||||
for (msgs) |msg| {
|
.Exited => |code| {
|
||||||
if (mem.endsWith(u8, msg.realpath, path) and mem.eql(u8, msg.text, text)) {
|
if (code != 0) {
|
||||||
const span = msg.getSpan();
|
std.debug.warn("elf file exited with code {}\n", .{code});
|
||||||
const first_token = msg.getTree().tokens.at(span.first);
|
return error.BinaryBadExitCode;
|
||||||
const last_token = msg.getTree().tokens.at(span.first);
|
|
||||||
const start_loc = msg.getTree().tokenLocationPtr(0, first_token);
|
|
||||||
if (start_loc.line + 1 == line and start_loc.column + 1 == column) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std.debug.warn("\n=====source:=======\n{}\n====expected:========\n{}:{}:{}: error: {}\n", .{
|
|
||||||
source,
|
|
||||||
path,
|
|
||||||
line,
|
|
||||||
column,
|
|
||||||
text,
|
|
||||||
});
|
|
||||||
std.debug.warn("\n====found:========\n", .{});
|
|
||||||
const stderr = std.io.getStdErr();
|
|
||||||
for (msgs) |msg| {
|
|
||||||
defer msg.destroy();
|
|
||||||
try msg.printToFile(stderr, errmsg.Color.Auto);
|
|
||||||
}
|
|
||||||
std.debug.warn("============\n", .{});
|
|
||||||
return error.TestFailed;
|
|
||||||
},
|
},
|
||||||
|
else => return error.BinaryCrashed,
|
||||||
}
|
}
|
||||||
|
std.testing.expectEqualSlices(u8, case.expected_stdout, exec_result.stdout);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn debugPrintErrors(src: []const u8, errors: var) void {
|
||||||
|
std.debug.warn("\n", .{});
|
||||||
|
var nl = true;
|
||||||
|
var line: usize = 1;
|
||||||
|
for (src) |byte| {
|
||||||
|
if (nl) {
|
||||||
|
std.debug.warn("{: >3}| ", .{line});
|
||||||
|
nl = false;
|
||||||
|
}
|
||||||
|
if (byte == '\n') {
|
||||||
|
nl = true;
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
std.debug.warn("{c}", .{byte});
|
||||||
|
}
|
||||||
|
std.debug.warn("\n", .{});
|
||||||
|
for (errors) |err_msg| {
|
||||||
|
const loc = std.zig.findLineColumn(src, err_msg.byte_offset);
|
||||||
|
std.debug.warn("{}:{}: error: {}\n", .{ loc.line + 1, loc.column + 1, err_msg.msg });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,24 +2,27 @@ const std = @import("std");
|
|||||||
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
||||||
|
|
||||||
pub fn addCases(ctx: *TestContext) !void {
|
pub fn addCases(ctx: *TestContext) !void {
|
||||||
// hello world
|
// TODO: re-enable these tests.
|
||||||
try ctx.testCompareOutputLibC(
|
// https://github.com/ziglang/zig/issues/1364
|
||||||
\\extern fn puts([*]const u8) void;
|
|
||||||
\\pub export fn main() c_int {
|
|
||||||
\\ puts("Hello, world!");
|
|
||||||
\\ return 0;
|
|
||||||
\\}
|
|
||||||
, "Hello, world!" ++ std.cstr.line_sep);
|
|
||||||
|
|
||||||
// function calling another function
|
//// hello world
|
||||||
try ctx.testCompareOutputLibC(
|
//try ctx.testCompareOutputLibC(
|
||||||
\\extern fn puts(s: [*]const u8) void;
|
// \\extern fn puts([*]const u8) void;
|
||||||
\\pub export fn main() c_int {
|
// \\pub export fn main() c_int {
|
||||||
\\ return foo("OK");
|
// \\ puts("Hello, world!");
|
||||||
\\}
|
// \\ return 0;
|
||||||
\\fn foo(s: [*]const u8) c_int {
|
// \\}
|
||||||
\\ puts(s);
|
//, "Hello, world!" ++ std.cstr.line_sep);
|
||||||
\\ return 0;
|
|
||||||
\\}
|
//// function calling another function
|
||||||
, "OK" ++ std.cstr.line_sep);
|
//try ctx.testCompareOutputLibC(
|
||||||
|
// \\extern fn puts(s: [*]const u8) void;
|
||||||
|
// \\pub export fn main() c_int {
|
||||||
|
// \\ return foo("OK");
|
||||||
|
// \\}
|
||||||
|
// \\fn foo(s: [*]const u8) c_int {
|
||||||
|
// \\ puts(s);
|
||||||
|
// \\ return 0;
|
||||||
|
// \\}
|
||||||
|
//, "OK" ++ std.cstr.line_sep);
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,57 @@
|
|||||||
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
||||||
|
|
||||||
pub fn addCases(ctx: *TestContext) !void {
|
pub fn addCases(ctx: *TestContext) !void {
|
||||||
try ctx.testCompileError(
|
// TODO: re-enable these tests.
|
||||||
\\export fn entry() void {}
|
// https://github.com/ziglang/zig/issues/1364
|
||||||
\\export fn entry() void {}
|
|
||||||
, "1.zig", 2, 8, "exported symbol collision: 'entry'");
|
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\fn() void {}
|
// \\export fn entry() void {}
|
||||||
, "1.zig", 1, 1, "missing function name");
|
// \\export fn entry() void {}
|
||||||
|
//, "1.zig", 2, 8, "exported symbol collision: 'entry'");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\comptime {
|
// \\fn() void {}
|
||||||
\\ return;
|
//, "1.zig", 1, 1, "missing function name");
|
||||||
\\}
|
|
||||||
, "1.zig", 2, 5, "return expression outside function definition");
|
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\export fn entry() void {
|
// \\comptime {
|
||||||
\\ defer return;
|
// \\ return;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 11, "cannot return from defer expression");
|
//, "1.zig", 2, 5, "return expression outside function definition");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\export fn entry() c_int {
|
// \\export fn entry() void {
|
||||||
\\ return 36893488147419103232;
|
// \\ defer return;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
|
//, "1.zig", 2, 11, "cannot return from defer expression");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\comptime {
|
// \\export fn entry() c_int {
|
||||||
\\ var a: *align(4) align(4) i32 = 0;
|
// \\ return 36893488147419103232;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 22, "Extra align qualifier");
|
//, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\comptime {
|
// \\comptime {
|
||||||
\\ var b: *const const i32 = 0;
|
// \\ var a: *align(4) align(4) i32 = 0;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 19, "Extra align qualifier");
|
//, "1.zig", 2, 22, "Extra align qualifier");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\comptime {
|
// \\comptime {
|
||||||
\\ var c: *volatile volatile i32 = 0;
|
// \\ var b: *const const i32 = 0;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 22, "Extra align qualifier");
|
//, "1.zig", 2, 19, "Extra align qualifier");
|
||||||
|
|
||||||
try ctx.testCompileError(
|
//try ctx.testCompileError(
|
||||||
\\comptime {
|
// \\comptime {
|
||||||
\\ var d: *allowzero allowzero i32 = 0;
|
// \\ var c: *volatile volatile i32 = 0;
|
||||||
\\}
|
// \\}
|
||||||
, "1.zig", 2, 23, "Extra align qualifier");
|
//, "1.zig", 2, 22, "Extra align qualifier");
|
||||||
|
|
||||||
|
//try ctx.testCompileError(
|
||||||
|
// \\comptime {
|
||||||
|
// \\ var d: *allowzero allowzero i32 = 0;
|
||||||
|
// \\}
|
||||||
|
//, "1.zig", 2, 23, "Extra align qualifier");
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,5 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
|||||||
pub fn addCases(ctx: *TestContext) !void {
|
pub fn addCases(ctx: *TestContext) !void {
|
||||||
try @import("compile_errors.zig").addCases(ctx);
|
try @import("compile_errors.zig").addCases(ctx);
|
||||||
try @import("compare_output.zig").addCases(ctx);
|
try @import("compare_output.zig").addCases(ctx);
|
||||||
|
@import("zir.zig").addCases(ctx);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
test "hello world IR" {
|
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
||||||
exeCmp(
|
|
||||||
|
pub fn addCases(ctx: *TestContext) void {
|
||||||
|
if (@import("std").Target.current.os.tag == .windows) {
|
||||||
|
// TODO implement self-hosted PE (.exe file) linking
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.addZIRCompareOutput("hello world ZIR",
|
||||||
\\@0 = str("Hello, world!\n")
|
\\@0 = str("Hello, world!\n")
|
||||||
\\@1 = primitive(void)
|
\\@1 = primitive(noreturn)
|
||||||
\\@2 = primitive(usize)
|
\\@2 = primitive(usize)
|
||||||
\\@3 = fntype([], @1, cc=Naked)
|
\\@3 = fntype([], @1, cc=Naked)
|
||||||
\\@4 = int(0)
|
\\@4 = int(0)
|
||||||
@ -50,5 +57,3 @@ test "hello world IR" {
|
|||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exeCmp(src: []const u8, expected_stdout: []const u8) void {}
|
|
Loading…
x
Reference in New Issue
Block a user