diff --git a/ci/zinc/linux_test.sh b/ci/zinc/linux_test.sh index 0213b20751..e24e8c2d53 100755 --- a/ci/zinc/linux_test.sh +++ b/ci/zinc/linux_test.sh @@ -62,12 +62,13 @@ stage3/bin/zig build test-fmt -fqemu -fwasmtime -Denable-llvm stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm +# https://github.com/ziglang/zig/issues/12144 +stage3/bin/zig build test-cases -fqemu -fwasmtime +stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm $STAGE1_ZIG build test-stack-traces -fqemu -fwasmtime $STAGE1_ZIG build test-run-translated-c -fqemu -fwasmtime $STAGE1_ZIG build docs -fqemu -fwasmtime -$STAGE1_ZIG build test-cases -fqemu -fwasmtime -$STAGE1_ZIG build test-link -fqemu -fwasmtime # Produce the experimental std lib documentation. mkdir -p "$RELEASE_STAGING/docs/std" diff --git a/lib/std/start.zig b/lib/std/start.zig index 788c979d48..8ea261be2d 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -455,10 +455,6 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { std.os.argv = argv[0..argc]; std.os.environ = envp; - if (builtin.zig_backend == .stage2_llvm) { - return @call(.{ .modifier = .always_inline }, callMain, .{}); - } - std.debug.maybeEnableSegfaultHandler(); return initEventLoopAndCallMain(); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b4bf8449ce..e7915e08b3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -673,6 +673,7 @@ pub const Object = struct { ) !void { const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); + const target = module.getTarget(); var dg: DeclGen = .{ .context = o.context, @@ -706,6 +707,17 @@ pub const Object = struct { DeclGen.removeFnAttr(llvm_func, "noinline"); } + // TODO: port these over from stage1 + // addLLVMFnAttr(llvm_fn, "sspstrong"); + // addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4"); + + // TODO: disable this if safety is off for the function scope + if (module.comp.bin_file.options.stack_check) { + dg.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack"); + } else if (target.os.tag == .uefi) { + dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); + } + // Remove all the basic blocks of a function in order to start over, generating // LLVM IR from an empty function body. while (llvm_func.getFirstBasicBlock()) |bb| { @@ -719,7 +731,6 @@ pub const Object = struct { // This gets the LLVM values from the function and stores them in `dg.args`. const fn_info = decl.ty.fnInfo(); - const target = dg.module.getTarget(); const sret = firstParamSRet(fn_info, target); const ret_ptr = if (sret) llvm_func.getParam(0) else null; const gpa = dg.gpa; @@ -730,7 +741,7 @@ pub const Object = struct { }; const err_return_tracing = fn_info.return_type.isError() and - dg.module.comp.bin_file.options.error_return_tracing; + module.comp.bin_file.options.error_return_tracing; const err_ret_trace = if (err_return_tracing) llvm_func.getParam(@boolToInt(ret_ptr != null)) @@ -920,7 +931,7 @@ pub const Object = struct { const line_number = decl.src_line + 1; const is_internal_linkage = decl.val.tag() != .extern_fn and - !dg.module.decl_exports.contains(decl_index); + !module.decl_exports.contains(decl_index); const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) llvm.DIFlags.NoReturn else @@ -936,7 +947,7 @@ pub const Object = struct { true, // is definition line_number + func.lbrace_line, // scope line llvm.DIFlags.StaticMember | noret_bit, - dg.module.comp.bin_file.options.optimize_mode != .Debug, + module.comp.bin_file.options.optimize_mode != .Debug, null, // decl_subprogram ); try dg.object.di_map.put(gpa, decl, subprogram.toNode()); diff --git a/src/link/C.zig b/src/link/C.zig index c56327ad63..6449be9c56 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -263,11 +263,13 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) // Covers zig.h and err_typedef_item. try f.all_buffers.ensureUnusedCapacity(gpa, 2); - f.all_buffers.appendAssumeCapacity(.{ - .iov_base = zig_h, - .iov_len = zig_h.len, - }); - f.file_size += zig_h.len; + if (zig_h.len != 0) { + f.all_buffers.appendAssumeCapacity(.{ + .iov_base = zig_h, + .iov_len = zig_h.len, + }); + f.file_size += zig_h.len; + } const err_typedef_writer = f.err_typedef_buf.writer(gpa); const err_typedef_index = f.all_buffers.items.len; @@ -301,11 +303,18 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) try flushDecl(self, &f, decl_index); } - f.all_buffers.items[err_typedef_index] = .{ - .iov_base = f.err_typedef_buf.items.ptr, - .iov_len = f.err_typedef_buf.items.len, - }; - f.file_size += f.err_typedef_buf.items.len; + if (f.err_typedef_buf.items.len == 0) { + f.all_buffers.items[err_typedef_index] = .{ + .iov_base = "", + .iov_len = 0, + }; + } else { + f.all_buffers.items[err_typedef_index] = .{ + .iov_base = f.err_typedef_buf.items.ptr, + .iov_len = f.err_typedef_buf.items.len, + }; + f.file_size += f.err_typedef_buf.items.len; + } // Now the function bodies. try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count); @@ -391,21 +400,25 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError! if (decl_block.fwd_decl.items.len != 0) { const buf = decl_block.fwd_decl.items; - try f.all_buffers.append(gpa, .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - f.file_size += buf.len; + if (buf.len != 0) { + try f.all_buffers.append(gpa, .{ + .iov_base = buf.ptr, + .iov_len = buf.len, + }); + f.file_size += buf.len; + } } if (decl.getFunction() != null) { f.fn_count += 1; } else if (decl_block.code.items.len != 0) { const buf = decl_block.code.items; - try f.all_buffers.append(gpa, .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - f.file_size += buf.len; + if (buf.len != 0) { + try f.all_buffers.append(gpa, .{ + .iov_base = buf.ptr, + .iov_len = buf.len, + }); + f.file_size += buf.len; + } } } @@ -421,19 +434,23 @@ pub fn flushEmitH(module: *Module) !void { defer all_buffers.deinit(); var file_size: u64 = zig_h.len; - all_buffers.appendAssumeCapacity(.{ - .iov_base = zig_h, - .iov_len = zig_h.len, - }); + if (zig_h.len != 0) { + all_buffers.appendAssumeCapacity(.{ + .iov_base = zig_h, + .iov_len = zig_h.len, + }); + } for (emit_h.decl_table.keys()) |decl_index| { const decl_emit_h = emit_h.declPtr(decl_index); const buf = decl_emit_h.fwd_decl.items; - all_buffers.appendAssumeCapacity(.{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - file_size += buf.len; + if (buf.len != 0) { + all_buffers.appendAssumeCapacity(.{ + .iov_base = buf.ptr, + .iov_len = buf.len, + }); + file_size += buf.len; + } } const directory = emit_h.loc.directory orelse module.comp.local_cache_directory; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index efbd86bc7f..03ba53801b 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1752,7 +1752,7 @@ fn pwriteDbgLineNops( .iov_base = buf.ptr, .iov_len = buf.len, }; - vec_index += 1; + if (buf.len > 0) vec_index += 1; { var padding_left = next_padding_size; @@ -1861,7 +1861,7 @@ fn pwriteDbgInfoNops( .iov_base = buf.ptr, .iov_len = buf.len, }; - vec_index += 1; + if (buf.len > 0) vec_index += 1; { var padding_left = next_padding_size; diff --git a/src/test.zig b/src/test.zig index 39061a98ff..5f4107a402 100644 --- a/src/test.zig +++ b/src/test.zig @@ -20,7 +20,7 @@ const enable_wasmtime: bool = build_options.enable_wasmtime; const enable_darling: bool = build_options.enable_darling; const enable_rosetta: bool = build_options.enable_rosetta; const glibc_runtimes_dir: ?[]const u8 = build_options.glibc_runtimes_dir; -const skip_stage1 = build_options.skip_stage1; +const skip_stage1 = builtin.zig_backend != .stage1 or build_options.skip_stage1; const hr = "=" ** 80; @@ -233,11 +233,11 @@ const TestManifest = struct { fn ConfigValueIterator(comptime T: type) type { return struct { inner: std.mem.SplitIterator(u8), - parse_fn: ParseFn(T), fn next(self: *@This()) !?T { const next_raw = self.inner.next() orelse return null; - return try self.parse_fn(next_raw); + const parseFn = getDefaultParser(T); + return try parseFn(next_raw); } }; } @@ -313,25 +313,15 @@ const TestManifest = struct { return manifest; } - fn getConfigForKeyCustomParser( - self: TestManifest, - key: []const u8, - comptime T: type, - parse_fn: ParseFn(T), - ) ConfigValueIterator(T) { - const bytes = self.config_map.get(key) orelse TestManifestConfigDefaults.get(self.@"type", key); - return ConfigValueIterator(T){ - .inner = std.mem.split(u8, bytes, ","), - .parse_fn = parse_fn, - }; - } - fn getConfigForKey( self: TestManifest, key: []const u8, comptime T: type, ) ConfigValueIterator(T) { - return self.getConfigForKeyCustomParser(key, T, getDefaultParser(T)); + const bytes = self.config_map.get(key) orelse TestManifestConfigDefaults.get(self.@"type", key); + return ConfigValueIterator(T){ + .inner = std.mem.split(u8, bytes, ","), + }; } fn getConfigForKeyAlloc( @@ -377,6 +367,15 @@ const TestManifest = struct { } fn getDefaultParser(comptime T: type) ParseFn(T) { + if (T == CrossTarget) return struct { + fn parse(str: []const u8) anyerror!T { + var opts = CrossTarget.ParseOptions{ + .arch_os_abi = str, + }; + return try CrossTarget.parse(opts); + } + }.parse; + switch (@typeInfo(T)) { .Int => return struct { fn parse(str: []const u8) anyerror!T { @@ -397,14 +396,7 @@ const TestManifest = struct { }; } }.parse, - .Struct => if (comptime std.mem.eql(u8, @typeName(T), "CrossTarget")) return struct { - fn parse(str: []const u8) anyerror!T { - var opts = CrossTarget.ParseOptions{ - .arch_os_abi = str, - }; - return try CrossTarget.parse(opts); - } - }.parse else @compileError("no default parser for " ++ @typeName(T)), + .Struct => @compileError("no default parser for " ++ @typeName(T)), else => @compileError("no default parser for " ++ @typeName(T)), } } @@ -884,8 +876,6 @@ pub const TestContext = struct { src: [:0]const u8, expected_errors: []const []const u8, ) void { - if (skip_stage1) return; - const case = ctx.addObj(name, .{}); case.backend = .stage1; case.addError(src, expected_errors); @@ -897,8 +887,6 @@ pub const TestContext = struct { src: [:0]const u8, expected_errors: []const []const u8, ) void { - if (skip_stage1) return; - const case = ctx.addTest(name, .{}); case.backend = .stage1; case.addError(src, expected_errors); @@ -910,8 +898,6 @@ pub const TestContext = struct { src: [:0]const u8, expected_errors: []const []const u8, ) void { - if (skip_stage1) return; - const case = ctx.addExe(name, .{}); case.backend = .stage1; case.addError(src, expected_errors); @@ -1143,8 +1129,6 @@ pub const TestContext = struct { // Cross-product to get all possible test combinations for (backends) |backend| { - if (backend == .stage1 and skip_stage1) continue; - for (targets) |target| { const name = try std.fmt.allocPrint(ctx.arena, "{s} ({s}, {s})", .{ name_prefix, @@ -1276,6 +1260,9 @@ pub const TestContext = struct { if (!build_options.have_llvm and case.backend == .llvm) continue; + if (skip_stage1 and case.backend == .stage1) + continue; + if (build_options.test_filter) |test_filter| { if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; } @@ -1607,6 +1594,7 @@ pub const TestContext = struct { var module_node = update_node.start("parse/analysis/codegen", 0); module_node.activate(); + module_node.context.refresh(); try comp.makeBinFileWritable(); try comp.update(); module_node.end(); @@ -1855,7 +1843,7 @@ pub const TestContext = struct { .qemu => |qemu_bin_name| if (enable_qemu) { const need_cross_glibc = target.isGnuLibC() and case.link_libc; - const glibc_dir_arg = if (need_cross_glibc) + const glibc_dir_arg: ?[]const u8 = if (need_cross_glibc) glibc_runtimes_dir orelse continue :update // glibc dir not available; pass test else null; diff --git a/test/cases/compile_errors/endless_loop_in_function_evaluation.zig b/test/cases/compile_errors/endless_loop_in_function_evaluation.zig deleted file mode 100644 index 7616bfa5e7..0000000000 --- a/test/cases/compile_errors/endless_loop_in_function_evaluation.zig +++ /dev/null @@ -1,15 +0,0 @@ -const seventh_fib_number = fibonacci(7); -fn fibonacci(x: i32) i32 { - return fibonacci(x - 1) + fibonacci(x - 2); -} - -export fn entry() usize { return @sizeOf(@TypeOf(&seventh_fib_number)); } - -// error -// backend=stage2 -// target=native -// -// :3:21: error: evaluation exceeded 1000 backwards branches -// :3:21: note: use @setEvalBranchQuota() to raise the branch limit from 1000 -// :3:21: note: called from here (999 times) -// :1:37: note: called from here