| author | |
| committer | |
| log | 2bae94280058f23ba44dc3857e2b551f5894e1cb |
| tree | 39483fa7a609f36b58dc19524e0b4467ab473974 |
| parent | b23a87953a7a4030af3d9acf8deacb85162dd275 |
15 files changed, 407 insertions(+), 377 deletions(-)
build.zig+1-2| ... | @@ -44,7 +44,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -44,7 +44,7 @@ pub fn build(b: *Builder) !void { |
| 44 | try findAndReadConfigH(b); | 44 | try findAndReadConfigH(b); |
| 45 | 45 | ||
| 46 | var test_stage2 = b.addTest("src-self-hosted/test.zig"); | 46 | var test_stage2 = b.addTest("src-self-hosted/test.zig"); |
| 47 | test_stage2.setBuildMode(builtin.Mode.Debug); | 47 | test_stage2.setBuildMode(.Debug); // note this is only the mode of the test harness |
| 48 | test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig"); | 48 | test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig"); |
| 49 | 49 | ||
| 50 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); | 50 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); |
| ... | @@ -68,7 +68,6 @@ pub fn build(b: *Builder) !void { | ... | @@ -68,7 +68,6 @@ pub fn build(b: *Builder) !void { |
| 68 | var ctx = parseConfigH(b, config_h_text); | 68 | var ctx = parseConfigH(b, config_h_text); |
| 69 | ctx.llvm = try findLLVM(b, ctx.llvm_config_exe); | 69 | ctx.llvm = try findLLVM(b, ctx.llvm_config_exe); |
| 70 | 70 | ||
| 71 | try configureStage2(b, test_stage2, ctx); | ||
| 72 | try configureStage2(b, exe, ctx); | 71 | try configureStage2(b, exe, ctx); |
| 73 | 72 | ||
| 74 | b.default_step.dependOn(&exe.step); | 73 | b.default_step.dependOn(&exe.step); |
lib/std/child_process.zig+11-1| ... | @@ -46,6 +46,12 @@ pub const ChildProcess = struct { | ... | @@ -46,6 +46,12 @@ pub const ChildProcess = struct { |
| 46 | 46 | ||
| 47 | /// Set to change the current working directory when spawning the child process. | 47 | /// Set to change the current working directory when spawning the child process. |
| 48 | cwd: ?[]const u8, | 48 | cwd: ?[]const u8, |
| 49 | /// Set to change the current working directory when spawning the child process. | ||
| 50 | /// This is not yet implemented for Windows. See https://github.com/ziglang/zig/issues/5190 | ||
| 51 | /// Once that is done, `cwd` will be deprecated in favor of this field. | ||
| 52 | /// The directory handle must be opened with the ability to be passed | ||
| 53 | /// to a child process (no `O_CLOEXEC` flag on POSIX). | ||
| 54 | cwd_dir: ?fs.Dir = null, | ||
| 49 | 55 | ||
| 50 | err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t, | 56 | err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t, |
| 51 | 57 | ||
| ... | @@ -183,6 +189,7 @@ pub const ChildProcess = struct { | ... | @@ -183,6 +189,7 @@ pub const ChildProcess = struct { |
| 183 | allocator: *mem.Allocator, | 189 | allocator: *mem.Allocator, |
| 184 | argv: []const []const u8, | 190 | argv: []const []const u8, |
| 185 | cwd: ?[]const u8 = null, | 191 | cwd: ?[]const u8 = null, |
| 192 | cwd_dir: ?fs.Dir = null, | ||
| 186 | env_map: ?*const BufMap = null, | 193 | env_map: ?*const BufMap = null, |
| 187 | max_output_bytes: usize = 50 * 1024, | 194 | max_output_bytes: usize = 50 * 1024, |
| 188 | expand_arg0: Arg0Expand = .no_expand, | 195 | expand_arg0: Arg0Expand = .no_expand, |
| ... | @@ -194,6 +201,7 @@ pub const ChildProcess = struct { | ... | @@ -194,6 +201,7 @@ pub const ChildProcess = struct { |
| 194 | child.stdout_behavior = .Pipe; | 201 | child.stdout_behavior = .Pipe; |
| 195 | child.stderr_behavior = .Pipe; | 202 | child.stderr_behavior = .Pipe; |
| 196 | child.cwd = args.cwd; | 203 | child.cwd = args.cwd; |
| 204 | child.cwd_dir = args.cwd_dir; | ||
| 197 | child.env_map = args.env_map; | 205 | child.env_map = args.env_map; |
| 198 | child.expand_arg0 = args.expand_arg0; | 206 | child.expand_arg0 = args.expand_arg0; |
| 199 | 207 | ||
| ... | @@ -414,7 +422,9 @@ pub const ChildProcess = struct { | ... | @@ -414,7 +422,9 @@ pub const ChildProcess = struct { |
| 414 | os.close(stderr_pipe[1]); | 422 | os.close(stderr_pipe[1]); |
| 415 | } | 423 | } |
| 416 | 424 | ||
| 417 | if (self.cwd) |cwd| { | 425 | if (self.cwd_dir) |cwd| { |
| 426 | os.fchdir(cwd.fd) catch |err| forkChildErrReport(err_pipe[1], err); | ||
| 427 | } else if (self.cwd) |cwd| { | ||
| 418 | os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err); | 428 | os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err); |
| 419 | } | 429 | } |
| 420 | 430 |
lib/std/fs.zig+22-4| ... | @@ -606,7 +606,8 @@ pub const Dir = struct { | ... | @@ -606,7 +606,8 @@ pub const Dir = struct { |
| 606 | } else 0; | 606 | } else 0; |
| 607 | 607 | ||
| 608 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 608 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 609 | const os_flags = lock_flag | O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read) | 609 | const O_CLOEXEC: u32 = if (flags.share_with_child_process) 0 else os.O_CLOEXEC; |
| 610 | const os_flags = lock_flag | O_LARGEFILE | O_CLOEXEC | if (flags.write and flags.read) | ||
| 610 | @as(u32, os.O_RDWR) | 611 | @as(u32, os.O_RDWR) |
| 611 | else if (flags.write) | 612 | else if (flags.write) |
| 612 | @as(u32, os.O_WRONLY) | 613 | @as(u32, os.O_WRONLY) |
| ... | @@ -689,7 +690,8 @@ pub const Dir = struct { | ... | @@ -689,7 +690,8 @@ pub const Dir = struct { |
| 689 | } else 0; | 690 | } else 0; |
| 690 | 691 | ||
| 691 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; | 692 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| 692 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC | | 693 | const O_CLOEXEC: u32 = if (flags.share_with_child_process) 0 else os.O_CLOEXEC; |
| 694 | const os_flags = lock_flag | O_LARGEFILE | os.O_CREAT | O_CLOEXEC | | ||
| 693 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | | 695 | (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) | |
| 694 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | | 696 | (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) | |
| 695 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); | 697 | (if (flags.exclusive) @as(u32, os.O_EXCL) else 0); |
| ... | @@ -787,6 +789,15 @@ pub const Dir = struct { | ... | @@ -787,6 +789,15 @@ pub const Dir = struct { |
| 787 | } | 789 | } |
| 788 | } | 790 | } |
| 789 | 791 | ||
| 792 | /// This function performs `makePath`, followed by `openDir`. | ||
| 793 | /// If supported by the OS, this operation is atomic. It is not atomic on | ||
| 794 | /// all operating systems. | ||
| 795 | pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir { | ||
| 796 | // TODO improve this implementation on Windows; we can avoid 1 call to NtClose | ||
| 797 | try self.makePath(sub_path); | ||
| 798 | return self.openDir(sub_path, open_dir_options); | ||
| 799 | } | ||
| 800 | |||
| 790 | /// Changes the current working directory to the open directory handle. | 801 | /// Changes the current working directory to the open directory handle. |
| 791 | /// This modifies global state and can have surprising effects in multi- | 802 | /// This modifies global state and can have surprising effects in multi- |
| 792 | /// threaded applications. Most applications and especially libraries should | 803 | /// threaded applications. Most applications and especially libraries should |
| ... | @@ -807,6 +818,11 @@ pub const Dir = struct { | ... | @@ -807,6 +818,11 @@ pub const Dir = struct { |
| 807 | /// `true` means the opened directory can be scanned for the files and sub-directories | 818 | /// `true` means the opened directory can be scanned for the files and sub-directories |
| 808 | /// of the result. It means the `iterate` function can be called. | 819 | /// of the result. It means the `iterate` function can be called. |
| 809 | iterate: bool = false, | 820 | iterate: bool = false, |
| 821 | |||
| 822 | /// `true` means the opened directory can be passed to a child process. | ||
| 823 | /// `false` means the directory handle is considered to be closed when a child | ||
| 824 | /// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX. | ||
| 825 | share_with_child_process: bool = false, | ||
| 810 | }; | 826 | }; |
| 811 | 827 | ||
| 812 | /// Opens a directory at the given path. The directory is a system resource that remains | 828 | /// Opens a directory at the given path. The directory is a system resource that remains |
| ... | @@ -832,9 +848,11 @@ pub const Dir = struct { | ... | @@ -832,9 +848,11 @@ pub const Dir = struct { |
| 832 | return self.openDirW(&sub_path_w, args); | 848 | return self.openDirW(&sub_path_w, args); |
| 833 | } else if (!args.iterate) { | 849 | } else if (!args.iterate) { |
| 834 | const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; | 850 | const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; |
| 835 | return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH); | 851 | const O_CLOEXEC: u32 = if (args.share_with_child_process) 0 else os.O_CLOEXEC; |
| 852 | return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | O_CLOEXEC | O_PATH); | ||
| 836 | } else { | 853 | } else { |
| 837 | return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC); | 854 | const O_CLOEXEC: u32 = if (args.share_with_child_process) 0 else os.O_CLOEXEC; |
| 855 | return self.openDirFlagsZ(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | O_CLOEXEC); | ||
| 838 | } | 856 | } |
| 839 | } | 857 | } |
| 840 | 858 |
lib/std/fs/file.zig+10| ... | @@ -69,6 +69,11 @@ pub const File = struct { | ... | @@ -69,6 +69,11 @@ pub const File = struct { |
| 69 | /// It allows the use of `noasync` when calling functions related to opening | 69 | /// It allows the use of `noasync` when calling functions related to opening |
| 70 | /// the file, reading, and writing. | 70 | /// the file, reading, and writing. |
| 71 | always_blocking: bool = false, | 71 | always_blocking: bool = false, |
| 72 | |||
| 73 | /// `true` means the opened directory can be passed to a child process. | ||
| 74 | /// `false` means the directory handle is considered to be closed when a child | ||
| 75 | /// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX. | ||
| 76 | share_with_child_process: bool = false, | ||
| 72 | }; | 77 | }; |
| 73 | 78 | ||
| 74 | /// TODO https://github.com/ziglang/zig/issues/3802 | 79 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| ... | @@ -107,6 +112,11 @@ pub const File = struct { | ... | @@ -107,6 +112,11 @@ pub const File = struct { |
| 107 | /// For POSIX systems this is the file system mode the file will | 112 | /// For POSIX systems this is the file system mode the file will |
| 108 | /// be created with. | 113 | /// be created with. |
| 109 | mode: Mode = default_mode, | 114 | mode: Mode = default_mode, |
| 115 | |||
| 116 | /// `true` means the opened directory can be passed to a child process. | ||
| 117 | /// `false` means the directory handle is considered to be closed when a child | ||
| 118 | /// process is spawned. This corresponds to the inverse of `O_CLOEXEC` on POSIX. | ||
| 119 | share_with_child_process: bool = false, | ||
| 110 | }; | 120 | }; |
| 111 | 121 | ||
| 112 | /// Upon success, the stream is in an uninitialized state. To continue using it, | 122 | /// Upon success, the stream is in an uninitialized state. To continue using it, |
lib/std/testing.zig+38| ... | @@ -193,6 +193,44 @@ pub fn expect(ok: bool) void { | ... | @@ -193,6 +193,44 @@ pub fn expect(ok: bool) void { |
| 193 | if (!ok) @panic("test failure"); | 193 | if (!ok) @panic("test failure"); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | pub const TmpDir = struct { | ||
| 197 | dir: std.fs.Dir, | ||
| 198 | parent_dir: std.fs.Dir, | ||
| 199 | sub_path: [sub_path_len]u8, | ||
| 200 | |||
| 201 | const random_bytes_count = 12; | ||
| 202 | const sub_path_len = std.base64.Base64Encoder.calcSize(random_bytes_count); | ||
| 203 | |||
| 204 | pub fn cleanup(self: *TmpDir) void { | ||
| 205 | self.dir.close(); | ||
| 206 | self.parent_dir.deleteTree(&self.sub_path) catch {}; | ||
| 207 | self.parent_dir.close(); | ||
| 208 | self.* = undefined; | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | |||
| 212 | pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { | ||
| 213 | var random_bytes: [TmpDir.random_bytes_count]u8 = undefined; | ||
| 214 | std.crypto.randomBytes(&random_bytes) catch | ||
| 215 | @panic("unable to make tmp dir for testing: unable to get random bytes"); | ||
| 216 | var sub_path: [TmpDir.sub_path_len]u8 = undefined; | ||
| 217 | std.fs.base64_encoder.encode(&sub_path, &random_bytes); | ||
| 218 | |||
| 219 | var cache_dir = std.fs.cwd().makeOpenPath("zig-cache", .{}) catch | ||
| 220 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache dir"); | ||
| 221 | defer cache_dir.close(); | ||
| 222 | var parent_dir = cache_dir.makeOpenPath("tmp", .{}) catch | ||
| 223 | @panic("unable to make tmp dir for testing: unable to make and open zig-cache/tmp dir"); | ||
| 224 | var dir = parent_dir.makeOpenPath(&sub_path, opts) catch | ||
| 225 | @panic("unable to make tmp dir for testing: unable to make and open the tmp dir"); | ||
| 226 | |||
| 227 | return .{ | ||
| 228 | .dir = dir, | ||
| 229 | .parent_dir = parent_dir, | ||
| 230 | .sub_path = sub_path, | ||
| 231 | }; | ||
| 232 | } | ||
| 233 | |||
| 196 | test "expectEqual nested array" { | 234 | test "expectEqual nested array" { |
| 197 | const a = [2][2]f32{ | 235 | const a = [2][2]f32{ |
| 198 | [_]f32{ 1.0, 0.0 }, | 236 | [_]f32{ 1.0, 0.0 }, |
lib/std/zig.zig+17| ... | @@ -9,6 +9,23 @@ pub const ast = @import("zig/ast.zig"); | ... | @@ -9,6 +9,23 @@ pub const ast = @import("zig/ast.zig"); |
| 9 | pub const system = @import("zig/system.zig"); | 9 | pub const system = @import("zig/system.zig"); |
| 10 | pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; | 10 | pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; |
| 11 | 11 | ||
| 12 | pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } { | ||
| 13 | var line: usize = 0; | ||
| 14 | var column: usize = 0; | ||
| 15 | for (source[0..byte_offset]) |byte| { | ||
| 16 | switch (byte) { | ||
| 17 | '\n' => { | ||
| 18 | line += 1; | ||
| 19 | column = 0; | ||
| 20 | }, | ||
| 21 | else => { | ||
| 22 | column += 1; | ||
| 23 | }, | ||
| 24 | } | ||
| 25 | } | ||
| 26 | return .{ .line = line, .column = column }; | ||
| 27 | } | ||
| 28 | |||
| 12 | test "" { | 29 | test "" { |
| 13 | @import("std").meta.refAllDecls(@This()); | 30 | @import("std").meta.refAllDecls(@This()); |
| 14 | } | 31 | } |
lib/std/zig/system.zig+6-1| ... | @@ -415,7 +415,12 @@ pub const NativeTargetInfo = struct { | ... | @@ -415,7 +415,12 @@ pub const NativeTargetInfo = struct { |
| 415 | // over our own shared objects and find a dynamic linker. | 415 | // over our own shared objects and find a dynamic linker. |
| 416 | self_exe: { | 416 | self_exe: { |
| 417 | const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator); | 417 | const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator); |
| 418 | defer allocator.free(lib_paths); | 418 | defer { |
| 419 | for (lib_paths) |lib_path| { | ||
| 420 | allocator.free(lib_path); | ||
| 421 | } | ||
| 422 | allocator.free(lib_paths); | ||
| 423 | } | ||
| 419 | 424 | ||
| 420 | var found_ld_info: LdInfo = undefined; | 425 | var found_ld_info: LdInfo = undefined; |
| 421 | var found_ld_path: [:0]const u8 = undefined; | 426 | var found_ld_path: [:0]const u8 = undefined; |
src-self-hosted/ir.zig+11-23| ... | @@ -4,10 +4,11 @@ const Allocator = std.mem.Allocator; | ... | @@ -4,10 +4,11 @@ const Allocator = std.mem.Allocator; |
| 4 | const Value = @import("value.zig").Value; | 4 | const Value = @import("value.zig").Value; |
| 5 | const Type = @import("type.zig").Type; | 5 | const Type = @import("type.zig").Type; |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const text = @import("ir/text.zig"); | ||
| 8 | const BigInt = std.math.big.Int; | 7 | const BigInt = std.math.big.Int; |
| 9 | const Target = std.Target; | 8 | const Target = std.Target; |
| 10 | 9 | ||
| 10 | pub const text = @import("ir/text.zig"); | ||
| 11 | |||
| 11 | /// These are in-memory, analyzed instructions. See `text.Inst` for the representation | 12 | /// These are in-memory, analyzed instructions. See `text.Inst` for the representation |
| 12 | /// of instructions that correspond to the ZIR text format. | 13 | /// of instructions that correspond to the ZIR text format. |
| 13 | /// This struct owns the `Value` and `Type` memory. When the struct is deallocated, | 14 | /// This struct owns the `Value` and `Type` memory. When the struct is deallocated, |
| ... | @@ -124,6 +125,10 @@ pub const Module = struct { | ... | @@ -124,6 +125,10 @@ pub const Module = struct { |
| 124 | pub fn deinit(self: *Module, allocator: *Allocator) void { | 125 | pub fn deinit(self: *Module, allocator: *Allocator) void { |
| 125 | allocator.free(self.exports); | 126 | allocator.free(self.exports); |
| 126 | allocator.free(self.errors); | 127 | allocator.free(self.errors); |
| 128 | for (self.fns) |f| { | ||
| 129 | allocator.free(f.body); | ||
| 130 | } | ||
| 131 | allocator.free(self.fns); | ||
| 127 | self.arena.deinit(); | 132 | self.arena.deinit(); |
| 128 | self.* = undefined; | 133 | self.* = undefined; |
| 129 | } | 134 | } |
| ... | @@ -795,7 +800,7 @@ pub fn main() anyerror!void { | ... | @@ -795,7 +800,7 @@ pub fn main() anyerror!void { |
| 795 | 800 | ||
| 796 | if (zir_module.errors.len != 0) { | 801 | if (zir_module.errors.len != 0) { |
| 797 | for (zir_module.errors) |err_msg| { | 802 | for (zir_module.errors) |err_msg| { |
| 798 | const loc = findLineColumn(source, err_msg.byte_offset); | 803 | const loc = std.zig.findLineColumn(source, err_msg.byte_offset); |
| 799 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); | 804 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); |
| 800 | } | 805 | } |
| 801 | if (debug_error_trace) return error.ParseFailure; | 806 | if (debug_error_trace) return error.ParseFailure; |
| ... | @@ -809,10 +814,10 @@ pub fn main() anyerror!void { | ... | @@ -809,10 +814,10 @@ pub fn main() anyerror!void { |
| 809 | 814 | ||
| 810 | if (analyzed_module.errors.len != 0) { | 815 | if (analyzed_module.errors.len != 0) { |
| 811 | for (analyzed_module.errors) |err_msg| { | 816 | for (analyzed_module.errors) |err_msg| { |
| 812 | const loc = findLineColumn(source, err_msg.byte_offset); | 817 | const loc = std.zig.findLineColumn(source, err_msg.byte_offset); |
| 813 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); | 818 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); |
| 814 | } | 819 | } |
| 815 | if (debug_error_trace) return error.ParseFailure; | 820 | if (debug_error_trace) return error.AnalysisFail; |
| 816 | std.process.exit(1); | 821 | std.process.exit(1); |
| 817 | } | 822 | } |
| 818 | 823 | ||
| ... | @@ -831,30 +836,13 @@ pub fn main() anyerror!void { | ... | @@ -831,30 +836,13 @@ pub fn main() anyerror!void { |
| 831 | defer result.deinit(allocator); | 836 | defer result.deinit(allocator); |
| 832 | if (result.errors.len != 0) { | 837 | if (result.errors.len != 0) { |
| 833 | for (result.errors) |err_msg| { | 838 | for (result.errors) |err_msg| { |
| 834 | const loc = findLineColumn(source, err_msg.byte_offset); | 839 | const loc = std.zig.findLineColumn(source, err_msg.byte_offset); |
| 835 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); | 840 | std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg }); |
| 836 | } | 841 | } |
| 837 | if (debug_error_trace) return error.ParseFailure; | 842 | if (debug_error_trace) return error.LinkFailure; |
| 838 | std.process.exit(1); | 843 | std.process.exit(1); |
| 839 | } | 844 | } |
| 840 | } | 845 | } |
| 841 | 846 | ||
| 842 | fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } { | ||
| 843 | var line: usize = 0; | ||
| 844 | var column: usize = 0; | ||
| 845 | for (source[0..byte_offset]) |byte| { | ||
| 846 | switch (byte) { | ||
| 847 | '\n' => { | ||
| 848 | line += 1; | ||
| 849 | column = 0; | ||
| 850 | }, | ||
| 851 | else => { | ||
| 852 | column += 1; | ||
| 853 | }, | ||
| 854 | } | ||
| 855 | } | ||
| 856 | return .{ .line = line, .column = column }; | ||
| 857 | } | ||
| 858 | |||
| 859 | // Performance optimization ideas: | 847 | // Performance optimization ideas: |
| 860 | // * when analyzing use a field in the Inst instead of HashMap to track corresponding instructions | 848 | // * when analyzing use a field in the Inst instead of HashMap to track corresponding instructions |
src-self-hosted/ir/text.zig+25-23| ... | @@ -532,9 +532,10 @@ const Parser = struct { | ... | @@ -532,9 +532,10 @@ const Parser = struct { |
| 532 | else => |byte| return self.failByte(byte), | 532 | else => |byte| return self.failByte(byte), |
| 533 | }; | 533 | }; |
| 534 | 534 | ||
| 535 | return Inst.Fn.Body{ | 535 | // Move the instructions to the arena |
| 536 | .instructions = body_context.instructions.toOwnedSlice(), | 536 | const instrs = try self.arena.allocator.alloc(*Inst, body_context.instructions.items.len); |
| 537 | }; | 537 | mem.copy(*Inst, instrs, body_context.instructions.items); |
| 538 | return Inst.Fn.Body{ .instructions = instrs }; | ||
| 538 | } | 539 | } |
| 539 | 540 | ||
| 540 | fn parseStringLiteral(self: *Parser) ![]u8 { | 541 | fn parseStringLiteral(self: *Parser) ![]u8 { |
| ... | @@ -588,26 +589,27 @@ const Parser = struct { | ... | @@ -588,26 +589,27 @@ const Parser = struct { |
| 588 | 589 | ||
| 589 | fn parseRoot(self: *Parser) !void { | 590 | fn parseRoot(self: *Parser) !void { |
| 590 | // The IR format is designed so that it can be tokenized and parsed at the same time. | 591 | // The IR format is designed so that it can be tokenized and parsed at the same time. |
| 591 | while (true) : (self.i += 1) switch (self.source[self.i]) { | 592 | while (true) { |
| 592 | ';' => _ = try skipToAndOver(self, '\n'), | 593 | switch (self.source[self.i]) { |
| 593 | '@' => { | 594 | ';' => _ = try skipToAndOver(self, '\n'), |
| 594 | self.i += 1; | 595 | '@' => { |
| 595 | const ident = try skipToAndOver(self, ' '); | 596 | self.i += 1; |
| 596 | skipSpace(self); | 597 | const ident = try skipToAndOver(self, ' '); |
| 597 | try requireEatBytes(self, "="); | 598 | skipSpace(self); |
| 598 | skipSpace(self); | 599 | try requireEatBytes(self, "="); |
| 599 | const inst = try parseInstruction(self, null); | 600 | skipSpace(self); |
| 600 | const ident_index = self.decls.items.len; | 601 | const inst = try parseInstruction(self, null); |
| 601 | if (try self.global_name_map.put(ident, ident_index)) |_| { | 602 | const ident_index = self.decls.items.len; |
| 602 | return self.fail("redefinition of identifier '{}'", .{ident}); | 603 | if (try self.global_name_map.put(ident, ident_index)) |_| { |
| 603 | } | 604 | return self.fail("redefinition of identifier '{}'", .{ident}); |
| 604 | try self.decls.append(inst); | 605 | } |
| 605 | continue; | 606 | try self.decls.append(inst); |
| 606 | }, | 607 | }, |
| 607 | ' ', '\n' => continue, | 608 | ' ', '\n' => self.i += 1, |
| 608 | 0 => break, | 609 | 0 => break, |
| 609 | else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}), | 610 | else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}), |
| 610 | }; | 611 | } |
| 612 | } | ||
| 611 | } | 613 | } |
| 612 | 614 | ||
| 613 | fn eatByte(self: *Parser, byte: u8) bool { | 615 | fn eatByte(self: *Parser, byte: u8) bool { |
src-self-hosted/test.zig+131-200| ... | @@ -1,237 +1,168 @@ | ... | @@ -1,237 +1,168 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const link = @import("link.zig"); |
| 3 | const Target = std.Target; | 3 | const ir = @import("ir.zig"); |
| 4 | const Compilation = @import("compilation.zig").Compilation; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const introspect = @import("introspect.zig"); | ||
| 6 | const testing = std.testing; | ||
| 7 | const errmsg = @import("errmsg.zig"); | ||
| 8 | const ZigCompiler = @import("compilation.zig").ZigCompiler; | ||
| 9 | 5 | ||
| 10 | var ctx: TestContext = undefined; | 6 | var global_ctx: TestContext = undefined; |
| 11 | 7 | ||
| 12 | test "stage2" { | 8 | test "self-hosted" { |
| 13 | // TODO provide a way to run tests in evented I/O mode | 9 | try global_ctx.init(); |
| 14 | if (!std.io.is_async) return error.SkipZigTest; | 10 | defer global_ctx.deinit(); |
| 15 | 11 | ||
| 16 | // TODO https://github.com/ziglang/zig/issues/1364 | 12 | try @import("stage2_tests").addCases(&global_ctx); |
| 17 | // TODO https://github.com/ziglang/zig/issues/3117 | ||
| 18 | if (true) return error.SkipZigTest; | ||
| 19 | 13 | ||
| 20 | try ctx.init(); | 14 | try global_ctx.run(); |
| 21 | defer ctx.deinit(); | ||
| 22 | |||
| 23 | try @import("stage2_tests").addCases(&ctx); | ||
| 24 | |||
| 25 | try ctx.run(); | ||
| 26 | } | 15 | } |
| 27 | 16 | ||
| 28 | const file1 = "1.zig"; | ||
| 29 | // TODO https://github.com/ziglang/zig/issues/3783 | ||
| 30 | const allocator = std.heap.page_allocator; | ||
| 31 | |||
| 32 | pub const TestContext = struct { | 17 | pub const TestContext = struct { |
| 33 | zig_compiler: ZigCompiler, | 18 | zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase), |
| 34 | zig_lib_dir: []u8, | 19 | |
| 35 | file_index: std.atomic.Int(usize), | 20 | pub const ZIRCompareOutputCase = struct { |
| 36 | group: std.event.Group(anyerror!void), | 21 | name: []const u8, |
| 37 | any_err: anyerror!void, | 22 | src: [:0]const u8, |
| 38 | 23 | expected_stdout: []const u8, | |
| 39 | const tmp_dir_name = "stage2_test_tmp"; | 24 | }; |
| 25 | |||
| 26 | pub fn addZIRCompareOutput( | ||
| 27 | ctx: *TestContext, | ||
| 28 | name: []const u8, | ||
| 29 | src: [:0]const u8, | ||
| 30 | expected_stdout: []const u8, | ||
| 31 | ) void { | ||
| 32 | ctx.zir_cmp_output_cases.append(.{ | ||
| 33 | .name = name, | ||
| 34 | .src = src, | ||
| 35 | .expected_stdout = expected_stdout, | ||
| 36 | }) catch unreachable; | ||
| 37 | } | ||
| 40 | 38 | ||
| 41 | fn init(self: *TestContext) !void { | 39 | fn init(self: *TestContext) !void { |
| 42 | self.* = TestContext{ | 40 | self.* = .{ |
| 43 | .any_err = {}, | 41 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), |
| 44 | .zig_compiler = undefined, | ||
| 45 | .zig_lib_dir = undefined, | ||
| 46 | .group = undefined, | ||
| 47 | .file_index = std.atomic.Int(usize).init(0), | ||
| 48 | }; | 42 | }; |
| 49 | |||
| 50 | self.zig_compiler = try ZigCompiler.init(allocator); | ||
| 51 | errdefer self.zig_compiler.deinit(); | ||
| 52 | |||
| 53 | self.group = std.event.Group(anyerror!void).init(allocator); | ||
| 54 | errdefer self.group.wait() catch {}; | ||
| 55 | |||
| 56 | self.zig_lib_dir = try introspect.resolveZigLibDir(allocator); | ||
| 57 | errdefer allocator.free(self.zig_lib_dir); | ||
| 58 | |||
| 59 | try std.fs.cwd().makePath(tmp_dir_name); | ||
| 60 | errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {}; | ||
| 61 | } | 43 | } |
| 62 | 44 | ||
| 63 | fn deinit(self: *TestContext) void { | 45 | fn deinit(self: *TestContext) void { |
| 64 | std.fs.cwd().deleteTree(tmp_dir_name) catch {}; | 46 | self.zir_cmp_output_cases.deinit(); |
| 65 | allocator.free(self.zig_lib_dir); | 47 | self.* = undefined; |
| 66 | self.zig_compiler.deinit(); | ||
| 67 | } | 48 | } |
| 68 | 49 | ||
| 69 | fn run(self: *TestContext) !void { | 50 | fn run(self: *TestContext) !void { |
| 70 | std.event.Loop.startCpuBoundOperation(); | 51 | var progress = std.Progress{}; |
| 71 | self.any_err = self.group.wait(); | 52 | const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len); |
| 72 | return self.any_err; | 53 | defer root_node.end(); |
| 54 | |||
| 55 | const native_info = try std.zig.system.NativeTargetInfo.detect(std.heap.page_allocator, .{}); | ||
| 56 | |||
| 57 | for (self.zir_cmp_output_cases.items) |case| { | ||
| 58 | std.testing.base_allocator_instance.reset(); | ||
| 59 | try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target); | ||
| 60 | try std.testing.allocator_instance.validate(); | ||
| 61 | } | ||
| 73 | } | 62 | } |
| 74 | 63 | ||
| 75 | fn testCompileError( | 64 | fn runOneZIRCmpOutputCase( |
| 76 | self: *TestContext, | 65 | self: *TestContext, |
| 77 | source: []const u8, | 66 | allocator: *Allocator, |
| 78 | path: []const u8, | 67 | root_node: *std.Progress.Node, |
| 79 | line: usize, | 68 | case: ZIRCompareOutputCase, |
| 80 | column: usize, | 69 | target: std.Target, |
| 81 | msg: []const u8, | ||
| 82 | ) !void { | 70 | ) !void { |
| 83 | var file_index_buf: [20]u8 = undefined; | 71 | var tmp = std.testing.tmpDir(.{ .share_with_child_process = true }); |
| 84 | const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()}); | 72 | defer tmp.cleanup(); |
| 85 | const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 }); | ||
| 86 | 73 | ||
| 87 | if (std.fs.path.dirname(file1_path)) |dirname| { | 74 | var prg_node = root_node.start(case.name, 4); |
| 88 | try std.fs.cwd().makePath(dirname); | 75 | prg_node.activate(); |
| 89 | } | 76 | defer prg_node.end(); |
| 90 | 77 | ||
| 91 | try std.fs.cwd().writeFile(file1_path, source); | 78 | var zir_module = x: { |
| 79 | var parse_node = prg_node.start("parse", null); | ||
| 80 | parse_node.activate(); | ||
| 81 | defer parse_node.end(); | ||
| 92 | 82 | ||
| 93 | var comp = try Compilation.create( | 83 | break :x try ir.text.parse(allocator, case.src); |
| 94 | &self.zig_compiler, | 84 | }; |
| 95 | "test", | 85 | defer zir_module.deinit(allocator); |
| 96 | file1_path, | 86 | if (zir_module.errors.len != 0) { |
| 97 | .Native, | 87 | debugPrintErrors(case.src, zir_module.errors); |
| 98 | .Obj, | 88 | return error.ParseFailure; |
| 99 | .Debug, | 89 | } |
| 100 | true, // is_static | ||
| 101 | self.zig_lib_dir, | ||
| 102 | ); | ||
| 103 | errdefer comp.destroy(); | ||
| 104 | |||
| 105 | comp.start(); | ||
| 106 | 90 | ||
| 107 | try self.group.call(getModuleEvent, comp, source, path, line, column, msg); | 91 | var analyzed_module = x: { |
| 108 | } | 92 | var analyze_node = prg_node.start("analyze", null); |
| 93 | analyze_node.activate(); | ||
| 94 | defer analyze_node.end(); | ||
| 109 | 95 | ||
| 110 | fn testCompareOutputLibC( | 96 | break :x try ir.analyze(allocator, zir_module, target); |
| 111 | self: *TestContext, | 97 | }; |
| 112 | source: []const u8, | 98 | defer analyzed_module.deinit(allocator); |
| 113 | expected_output: []const u8, | 99 | if (analyzed_module.errors.len != 0) { |
| 114 | ) !void { | 100 | debugPrintErrors(case.src, analyzed_module.errors); |
| 115 | var file_index_buf: [20]u8 = undefined; | 101 | return error.ParseFailure; |
| 116 | const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()}); | 102 | } |
| 117 | const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 }); | ||
| 118 | 103 | ||
| 119 | const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() }); | 104 | var link_result = x: { |
| 120 | if (std.fs.path.dirname(file1_path)) |dirname| { | 105 | var link_node = prg_node.start("link", null); |
| 121 | try std.fs.cwd().makePath(dirname); | 106 | link_node.activate(); |
| 107 | defer link_node.end(); | ||
| 108 | |||
| 109 | break :x try link.updateExecutableFilePath( | ||
| 110 | allocator, | ||
| 111 | analyzed_module, | ||
| 112 | tmp.dir, | ||
| 113 | "a.out", | ||
| 114 | ); | ||
| 115 | }; | ||
| 116 | defer link_result.deinit(allocator); | ||
| 117 | if (link_result.errors.len != 0) { | ||
| 118 | debugPrintErrors(case.src, link_result.errors); | ||
| 119 | return error.LinkFailure; | ||
| 122 | } | 120 | } |
| 123 | 121 | ||
| 124 | try std.fs.cwd().writeFile(file1_path, source); | 122 | var exec_result = x: { |
| 125 | 123 | var exec_node = prg_node.start("execute", null); | |
| 126 | var comp = try Compilation.create( | 124 | exec_node.activate(); |
| 127 | &self.zig_compiler, | 125 | defer exec_node.end(); |
| 128 | "test", | ||
| 129 | file1_path, | ||
| 130 | .Native, | ||
| 131 | .Exe, | ||
| 132 | .Debug, | ||
| 133 | false, | ||
| 134 | self.zig_lib_dir, | ||
| 135 | ); | ||
| 136 | errdefer comp.destroy(); | ||
| 137 | |||
| 138 | _ = try comp.addLinkLib("c", true); | ||
| 139 | comp.link_out_file = output_file; | ||
| 140 | comp.start(); | ||
| 141 | |||
| 142 | try self.group.call(getModuleEventSuccess, comp, output_file, expected_output); | ||
| 143 | } | ||
| 144 | 126 | ||
| 145 | async fn getModuleEventSuccess( | 127 | break :x try std.ChildProcess.exec(.{ |
| 146 | comp: *Compilation, | 128 | .allocator = allocator, |
| 147 | exe_file: []const u8, | 129 | .argv = &[_][]const u8{"./a.out"}, |
| 148 | expected_output: []const u8, | 130 | .cwd_dir = tmp.dir, |
| 149 | ) anyerror!void { | 131 | }); |
| 150 | defer comp.destroy(); | 132 | }; |
| 151 | const build_event = comp.events.get(); | 133 | defer allocator.free(exec_result.stdout); |
| 152 | 134 | defer allocator.free(exec_result.stderr); | |
| 153 | switch (build_event) { | 135 | switch (exec_result.term) { |
| 154 | .Ok => { | 136 | .Exited => |code| { |
| 155 | const argv = [_][]const u8{exe_file}; | 137 | if (code != 0) { |
| 156 | // TODO use event loop | 138 | std.debug.warn("elf file exited with code {}\n", .{code}); |
| 157 | const child = try std.ChildProcess.exec(.{ | 139 | return error.BinaryBadExitCode; |
| 158 | .allocator = allocator, | ||
| 159 | .argv = argv, | ||
| 160 | .max_output_bytes = 1024 * 1024, | ||
| 161 | }); | ||
| 162 | switch (child.term) { | ||
| 163 | .Exited => |code| { | ||
| 164 | if (code != 0) { | ||
| 165 | return error.BadReturnCode; | ||
| 166 | } | ||
| 167 | }, | ||
| 168 | else => { | ||
| 169 | return error.Crashed; | ||
| 170 | }, | ||
| 171 | } | ||
| 172 | if (!mem.eql(u8, child.stdout, expected_output)) { | ||
| 173 | return error.OutputMismatch; | ||
| 174 | } | ||
| 175 | }, | ||
| 176 | .Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err, | ||
| 177 | .Fail => |msgs| { | ||
| 178 | const stderr = std.io.getStdErr(); | ||
| 179 | try stderr.write("build incorrectly failed:\n"); | ||
| 180 | for (msgs) |msg| { | ||
| 181 | defer msg.destroy(); | ||
| 182 | try msg.printToFile(stderr, .Auto); | ||
| 183 | } | 140 | } |
| 184 | }, | 141 | }, |
| 142 | else => return error.BinaryCrashed, | ||
| 185 | } | 143 | } |
| 144 | std.testing.expectEqualSlices(u8, case.expected_stdout, exec_result.stdout); | ||
| 186 | } | 145 | } |
| 146 | }; | ||
| 187 | 147 | ||
| 188 | async fn getModuleEvent( | 148 | fn debugPrintErrors(src: []const u8, errors: var) void { |
| 189 | comp: *Compilation, | 149 | std.debug.warn("\n", .{}); |
| 190 | source: []const u8, | 150 | var nl = true; |
| 191 | path: []const u8, | 151 | var line: usize = 1; |
| 192 | line: usize, | 152 | for (src) |byte| { |
| 193 | column: usize, | 153 | if (nl) { |
| 194 | text: []const u8, | 154 | std.debug.warn("{: >3}| ", .{line}); |
| 195 | ) anyerror!void { | 155 | nl = false; |
| 196 | defer comp.destroy(); | ||
| 197 | const build_event = comp.events.get(); | ||
| 198 | |||
| 199 | switch (build_event) { | ||
| 200 | .Ok => { | ||
| 201 | @panic("build incorrectly succeeded"); | ||
| 202 | }, | ||
| 203 | .Error => |err| { | ||
| 204 | @panic("build incorrectly failed"); | ||
| 205 | }, | ||
| 206 | .Fail => |msgs| { | ||
| 207 | testing.expect(msgs.len != 0); | ||
| 208 | for (msgs) |msg| { | ||
| 209 | if (mem.endsWith(u8, msg.realpath, path) and mem.eql(u8, msg.text, text)) { | ||
| 210 | const span = msg.getSpan(); | ||
| 211 | const first_token = msg.getTree().tokens.at(span.first); | ||
| 212 | const last_token = msg.getTree().tokens.at(span.first); | ||
| 213 | const start_loc = msg.getTree().tokenLocationPtr(0, first_token); | ||
| 214 | if (start_loc.line + 1 == line and start_loc.column + 1 == column) { | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | std.debug.warn("\n=====source:=======\n{}\n====expected:========\n{}:{}:{}: error: {}\n", .{ | ||
| 220 | source, | ||
| 221 | path, | ||
| 222 | line, | ||
| 223 | column, | ||
| 224 | text, | ||
| 225 | }); | ||
| 226 | std.debug.warn("\n====found:========\n", .{}); | ||
| 227 | const stderr = std.io.getStdErr(); | ||
| 228 | for (msgs) |msg| { | ||
| 229 | defer msg.destroy(); | ||
| 230 | try msg.printToFile(stderr, errmsg.Color.Auto); | ||
| 231 | } | ||
| 232 | std.debug.warn("============\n", .{}); | ||
| 233 | return error.TestFailed; | ||
| 234 | }, | ||
| 235 | } | 156 | } |
| 157 | if (byte == '\n') { | ||
| 158 | nl = true; | ||
| 159 | line += 1; | ||
| 160 | } | ||
| 161 | std.debug.warn("{c}", .{byte}); | ||
| 236 | } | 162 | } |
| 237 | }; | 163 | std.debug.warn("\n", .{}); |
| 164 | for (errors) |err_msg| { | ||
| 165 | const loc = std.zig.findLineColumn(src, err_msg.byte_offset); | ||
| 166 | std.debug.warn("{}:{}: error: {}\n", .{ loc.line + 1, loc.column + 1, err_msg.msg }); | ||
| 167 | } | ||
| 168 | } |
test/stage2/compare_output.zig+22-19| ... | @@ -2,24 +2,27 @@ const std = @import("std"); | ... | @@ -2,24 +2,27 @@ const std = @import("std"); |
| 2 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | 2 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; |
| 3 | 3 | ||
| 4 | pub fn addCases(ctx: *TestContext) !void { | 4 | pub fn addCases(ctx: *TestContext) !void { |
| 5 | // hello world | 5 | // TODO: re-enable these tests. |
| 6 | try ctx.testCompareOutputLibC( | 6 | // https://github.com/ziglang/zig/issues/1364 |
| 7 | \\extern fn puts([*]const u8) void; | ||
| 8 | \\pub export fn main() c_int { | ||
| 9 | \\ puts("Hello, world!"); | ||
| 10 | \\ return 0; | ||
| 11 | \\} | ||
| 12 | , "Hello, world!" ++ std.cstr.line_sep); | ||
| 13 | 7 | ||
| 14 | // function calling another function | 8 | //// hello world |
| 15 | try ctx.testCompareOutputLibC( | 9 | //try ctx.testCompareOutputLibC( |
| 16 | \\extern fn puts(s: [*]const u8) void; | 10 | // \\extern fn puts([*]const u8) void; |
| 17 | \\pub export fn main() c_int { | 11 | // \\pub export fn main() c_int { |
| 18 | \\ return foo("OK"); | 12 | // \\ puts("Hello, world!"); |
| 19 | \\} | 13 | // \\ return 0; |
| 20 | \\fn foo(s: [*]const u8) c_int { | 14 | // \\} |
| 21 | \\ puts(s); | 15 | //, "Hello, world!" ++ std.cstr.line_sep); |
| 22 | \\ return 0; | 16 | |
| 23 | \\} | 17 | //// function calling another function |
| 24 | , "OK" ++ std.cstr.line_sep); | 18 | //try ctx.testCompareOutputLibC( |
| 19 | // \\extern fn puts(s: [*]const u8) void; | ||
| 20 | // \\pub export fn main() c_int { | ||
| 21 | // \\ return foo("OK"); | ||
| 22 | // \\} | ||
| 23 | // \\fn foo(s: [*]const u8) c_int { | ||
| 24 | // \\ puts(s); | ||
| 25 | // \\ return 0; | ||
| 26 | // \\} | ||
| 27 | //, "OK" ++ std.cstr.line_sep); | ||
| 25 | } | 28 | } |
test/stage2/compile_errors.zig+53-50| ... | @@ -1,54 +1,57 @@ | ... | @@ -1,54 +1,57 @@ |
| 1 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | 1 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; |
| 2 | 2 | ||
| 3 | pub fn addCases(ctx: *TestContext) !void { | 3 | pub fn addCases(ctx: *TestContext) !void { |
| 4 | try ctx.testCompileError( | 4 | // TODO: re-enable these tests. |
| 5 | \\export fn entry() void {} | 5 | // https://github.com/ziglang/zig/issues/1364 |
| 6 | \\export fn entry() void {} | 6 | |
| 7 | , "1.zig", 2, 8, "exported symbol collision: 'entry'"); | 7 | //try ctx.testCompileError( |
| 8 | 8 | // \\export fn entry() void {} | |
| 9 | try ctx.testCompileError( | 9 | // \\export fn entry() void {} |
| 10 | \\fn() void {} | 10 | //, "1.zig", 2, 8, "exported symbol collision: 'entry'"); |
| 11 | , "1.zig", 1, 1, "missing function name"); | 11 | |
| 12 | 12 | //try ctx.testCompileError( | |
| 13 | try ctx.testCompileError( | 13 | // \\fn() void {} |
| 14 | \\comptime { | 14 | //, "1.zig", 1, 1, "missing function name"); |
| 15 | \\ return; | 15 | |
| 16 | \\} | 16 | //try ctx.testCompileError( |
| 17 | , "1.zig", 2, 5, "return expression outside function definition"); | 17 | // \\comptime { |
| 18 | 18 | // \\ return; | |
| 19 | try ctx.testCompileError( | 19 | // \\} |
| 20 | \\export fn entry() void { | 20 | //, "1.zig", 2, 5, "return expression outside function definition"); |
| 21 | \\ defer return; | 21 | |
| 22 | \\} | 22 | //try ctx.testCompileError( |
| 23 | , "1.zig", 2, 11, "cannot return from defer expression"); | 23 | // \\export fn entry() void { |
| 24 | 24 | // \\ defer return; | |
| 25 | try ctx.testCompileError( | 25 | // \\} |
| 26 | \\export fn entry() c_int { | 26 | //, "1.zig", 2, 11, "cannot return from defer expression"); |
| 27 | \\ return 36893488147419103232; | 27 | |
| 28 | \\} | 28 | //try ctx.testCompileError( |
| 29 | , "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); | 29 | // \\export fn entry() c_int { |
| 30 | 30 | // \\ return 36893488147419103232; | |
| 31 | try ctx.testCompileError( | 31 | // \\} |
| 32 | \\comptime { | 32 | //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); |
| 33 | \\ var a: *align(4) align(4) i32 = 0; | 33 | |
| 34 | \\} | 34 | //try ctx.testCompileError( |
| 35 | , "1.zig", 2, 22, "Extra align qualifier"); | 35 | // \\comptime { |
| 36 | 36 | // \\ var a: *align(4) align(4) i32 = 0; | |
| 37 | try ctx.testCompileError( | 37 | // \\} |
| 38 | \\comptime { | 38 | //, "1.zig", 2, 22, "Extra align qualifier"); |
| 39 | \\ var b: *const const i32 = 0; | 39 | |
| 40 | \\} | 40 | //try ctx.testCompileError( |
| 41 | , "1.zig", 2, 19, "Extra align qualifier"); | 41 | // \\comptime { |
| 42 | 42 | // \\ var b: *const const i32 = 0; | |
| 43 | try ctx.testCompileError( | 43 | // \\} |
| 44 | \\comptime { | 44 | //, "1.zig", 2, 19, "Extra align qualifier"); |
| 45 | \\ var c: *volatile volatile i32 = 0; | 45 | |
| 46 | \\} | 46 | //try ctx.testCompileError( |
| 47 | , "1.zig", 2, 22, "Extra align qualifier"); | 47 | // \\comptime { |
| 48 | 48 | // \\ var c: *volatile volatile i32 = 0; | |
| 49 | try ctx.testCompileError( | 49 | // \\} |
| 50 | \\comptime { | 50 | //, "1.zig", 2, 22, "Extra align qualifier"); |
| 51 | \\ var d: *allowzero allowzero i32 = 0; | 51 | |
| 52 | \\} | 52 | //try ctx.testCompileError( |
| 53 | , "1.zig", 2, 23, "Extra align qualifier"); | 53 | // \\comptime { |
| 54 | // \\ var d: *allowzero allowzero i32 = 0; | ||
| 55 | // \\} | ||
| 56 | //, "1.zig", 2, 23, "Extra align qualifier"); | ||
| 54 | } | 57 | } |
test/stage2/ir.zig deleted-54| ... | @@ -1,54 +0,0 @@ | ||
| 1 | test "hello world IR" { | ||
| 2 | exeCmp( | ||
| 3 | \\@0 = str("Hello, world!\n") | ||
| 4 | \\@1 = primitive(void) | ||
| 5 | \\@2 = primitive(usize) | ||
| 6 | \\@3 = fntype([], @1, cc=Naked) | ||
| 7 | \\@4 = int(0) | ||
| 8 | \\@5 = int(1) | ||
| 9 | \\@6 = int(231) | ||
| 10 | \\@7 = str("len") | ||
| 11 | \\ | ||
| 12 | \\@8 = fn(@3, { | ||
| 13 | \\ %0 = as(@2, @5) ; SYS_write | ||
| 14 | \\ %1 = as(@2, @5) ; STDOUT_FILENO | ||
| 15 | \\ %2 = ptrtoint(@0) ; msg ptr | ||
| 16 | \\ %3 = fieldptr(@0, @7) ; msg len ptr | ||
| 17 | \\ %4 = deref(%3) ; msg len | ||
| 18 | \\ %sysoutreg = str("={rax}") | ||
| 19 | \\ %rax = str("{rax}") | ||
| 20 | \\ %rdi = str("{rdi}") | ||
| 21 | \\ %rsi = str("{rsi}") | ||
| 22 | \\ %rdx = str("{rdx}") | ||
| 23 | \\ %rcx = str("rcx") | ||
| 24 | \\ %r11 = str("r11") | ||
| 25 | \\ %memory = str("memory") | ||
| 26 | \\ %syscall = str("syscall") | ||
| 27 | \\ %5 = asm(%syscall, @2, | ||
| 28 | \\ volatile=1, | ||
| 29 | \\ output=%sysoutreg, | ||
| 30 | \\ inputs=[%rax, %rdi, %rsi, %rdx], | ||
| 31 | \\ clobbers=[%rcx, %r11, %memory], | ||
| 32 | \\ args=[%0, %1, %2, %4]) | ||
| 33 | \\ | ||
| 34 | \\ %6 = as(@2, @6) ;SYS_exit_group | ||
| 35 | \\ %7 = as(@2, @4) ;exit code | ||
| 36 | \\ %8 = asm(%syscall, @2, | ||
| 37 | \\ volatile=1, | ||
| 38 | \\ output=%sysoutreg, | ||
| 39 | \\ inputs=[%rax, %rdi], | ||
| 40 | \\ clobbers=[%rcx, %r11, %memory], | ||
| 41 | \\ args=[%6, %7]) | ||
| 42 | \\ | ||
| 43 | \\ %9 = unreachable() | ||
| 44 | \\}) | ||
| 45 | \\ | ||
| 46 | \\@9 = str("_start") | ||
| 47 | \\@10 = export(@9, @8) | ||
| 48 | , | ||
| 49 | \\Hello, world! | ||
| 50 | \\ | ||
| 51 | ); | ||
| 52 | } | ||
| 53 | |||
| 54 | fn exeCmp(src: []const u8, expected_stdout: []const u8) void {} | ||
test/stage2/test.zig+1| ... | @@ -3,4 +3,5 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | ... | @@ -3,4 +3,5 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext; |
| 3 | pub fn addCases(ctx: *TestContext) !void { | 3 | pub fn addCases(ctx: *TestContext) !void { |
| 4 | try @import("compile_errors.zig").addCases(ctx); | 4 | try @import("compile_errors.zig").addCases(ctx); |
| 5 | try @import("compare_output.zig").addCases(ctx); | 5 | try @import("compare_output.zig").addCases(ctx); |
| 6 | @import("zir.zig").addCases(ctx); | ||
| 6 | } | 7 | } |
test/stage2/zir.zig created+59| ... | @@ -0,0 +1,59 @@ | ||
| 1 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | ||
| 2 | |||
| 3 | pub fn addCases(ctx: *TestContext) void { | ||
| 4 | if (@import("std").Target.current.os.tag == .windows) { | ||
| 5 | // TODO implement self-hosted PE (.exe file) linking | ||
| 6 | return; | ||
| 7 | } | ||
| 8 | |||
| 9 | ctx.addZIRCompareOutput("hello world ZIR", | ||
| 10 | \\@0 = str("Hello, world!\n") | ||
| 11 | \\@1 = primitive(noreturn) | ||
| 12 | \\@2 = primitive(usize) | ||
| 13 | \\@3 = fntype([], @1, cc=Naked) | ||
| 14 | \\@4 = int(0) | ||
| 15 | \\@5 = int(1) | ||
| 16 | \\@6 = int(231) | ||
| 17 | \\@7 = str("len") | ||
| 18 | \\ | ||
| 19 | \\@8 = fn(@3, { | ||
| 20 | \\ %0 = as(@2, @5) ; SYS_write | ||
| 21 | \\ %1 = as(@2, @5) ; STDOUT_FILENO | ||
| 22 | \\ %2 = ptrtoint(@0) ; msg ptr | ||
| 23 | \\ %3 = fieldptr(@0, @7) ; msg len ptr | ||
| 24 | \\ %4 = deref(%3) ; msg len | ||
| 25 | \\ %sysoutreg = str("={rax}") | ||
| 26 | \\ %rax = str("{rax}") | ||
| 27 | \\ %rdi = str("{rdi}") | ||
| 28 | \\ %rsi = str("{rsi}") | ||
| 29 | \\ %rdx = str("{rdx}") | ||
| 30 | \\ %rcx = str("rcx") | ||
| 31 | \\ %r11 = str("r11") | ||
| 32 | \\ %memory = str("memory") | ||
| 33 | \\ %syscall = str("syscall") | ||
| 34 | \\ %5 = asm(%syscall, @2, | ||
| 35 | \\ volatile=1, | ||
| 36 | \\ output=%sysoutreg, | ||
| 37 | \\ inputs=[%rax, %rdi, %rsi, %rdx], | ||
| 38 | \\ clobbers=[%rcx, %r11, %memory], | ||
| 39 | \\ args=[%0, %1, %2, %4]) | ||
| 40 | \\ | ||
| 41 | \\ %6 = as(@2, @6) ;SYS_exit_group | ||
| 42 | \\ %7 = as(@2, @4) ;exit code | ||
| 43 | \\ %8 = asm(%syscall, @2, | ||
| 44 | \\ volatile=1, | ||
| 45 | \\ output=%sysoutreg, | ||
| 46 | \\ inputs=[%rax, %rdi], | ||
| 47 | \\ clobbers=[%rcx, %r11, %memory], | ||
| 48 | \\ args=[%6, %7]) | ||
| 49 | \\ | ||
| 50 | \\ %9 = unreachable() | ||
| 51 | \\}) | ||
| 52 | \\ | ||
| 53 | \\@9 = str("_start") | ||
| 54 | \\@10 = export(@9, @8) | ||
| 55 | , | ||
| 56 | \\Hello, world! | ||
| 57 | \\ | ||
| 58 | ); | ||
| 59 | } | ||