From 27572373325b22b06767bc42cb7e270bf619f0a9 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 19 Mar 2022 13:36:16 +0200 Subject: [PATCH 1/3] Sema: add error for runtime block peer type being comptime only --- src/Sema.zig | 143 ++++++++++++++++++++++++++-------------- test/behavior/basic.zig | 3 +- 2 files changed, 95 insertions(+), 51 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index b798405d80..f8a5c28b80 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3930,6 +3930,23 @@ fn analyzeBlockBody( // to emit a jump instruction to after the block when it encounters the break. try parent_block.instructions.append(gpa, merges.block_inst); const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none); + + const type_src = src; // TODO: better source location + const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false); + if (!valid_rt) { + const msg = msg: { + const msg = try sema.errMsg(child_block, type_src, "value with comptime only type '{}' depends on runtime control flow", .{resolved_ty}); + errdefer msg.destroy(sema.gpa); + + const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; + try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); + + try sema.explainWhyTypeIsComptime(child_block, type_src, msg, type_src.toSrcLoc(child_block.src_decl), resolved_ty); + + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(child_block, msg); + } const ty_inst = try sema.addType(resolved_ty); try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len); @@ -4191,6 +4208,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError const br_ref = try start_block.addBr(label.merges.block_inst, operand); try label.merges.results.append(sema.gpa, operand); try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?); + block.runtime_index += 1; + if (block.runtime_cond == null and block.runtime_loop == null) { + block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop; + block.runtime_loop = start_block.runtime_loop; + } return inst; } } @@ -15447,56 +15469,7 @@ fn validateVarType( var_ty: Type, is_extern: bool, ) CompileError!void { - var ty = var_ty; - while (true) switch (ty.zigTypeTag()) { - .Bool, - .Int, - .Float, - .ErrorSet, - .Enum, - .Frame, - .AnyFrame, - .Void, - => return, - - .BoundFn, - .ComptimeFloat, - .ComptimeInt, - .EnumLiteral, - .NoReturn, - .Type, - .Undefined, - .Null, - .Fn, - => break, - - .Pointer => { - const elem_ty = ty.childType(); - switch (elem_ty.zigTypeTag()) { - .Opaque, .Fn => return, - else => ty = elem_ty, - } - }, - .Opaque => if (is_extern) return else break, - - .Optional => { - var buf: Type.Payload.ElemType = undefined; - const child_ty = ty.optionalChild(&buf); - return validateVarType(sema, block, src, child_ty, is_extern); - }, - .Array, .Vector => ty = ty.elemType(), - - .ErrorUnion => ty = ty.errorUnionPayload(), - - .Struct, .Union => { - const resolved_ty = try sema.resolveTypeFields(block, src, ty); - if (try sema.typeRequiresComptime(block, src, resolved_ty)) { - break; - } else { - return; - } - }, - } else unreachable; // TODO should not need else unreachable + if (try sema.validateRunTimeType(block, src, var_ty, is_extern)) return; const msg = msg: { const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty}); @@ -15509,6 +15482,62 @@ fn validateVarType( return sema.failWithOwnedErrorMsg(block, msg); } +fn validateRunTimeType( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + var_ty: Type, + is_extern: bool, +) CompileError!bool { + var ty = var_ty; + while (true) switch (ty.zigTypeTag()) { + .Bool, + .Int, + .Float, + .ErrorSet, + .Enum, + .Frame, + .AnyFrame, + .Void, + => return true, + + .BoundFn, + .ComptimeFloat, + .ComptimeInt, + .EnumLiteral, + .NoReturn, + .Type, + .Undefined, + .Null, + .Fn, + => return false, + + .Pointer => { + const elem_ty = ty.childType(); + switch (elem_ty.zigTypeTag()) { + .Opaque, .Fn => return true, + else => ty = elem_ty, + } + }, + .Opaque => return is_extern, + + .Optional => { + var buf: Type.Payload.ElemType = undefined; + const child_ty = ty.optionalChild(&buf); + return validateRunTimeType(sema, block, src, child_ty, is_extern); + }, + .Array, .Vector => ty = ty.elemType(), + + .ErrorUnion => ty = ty.errorUnionPayload(), + + .Struct, .Union => { + const resolved_ty = try sema.resolveTypeFields(block, src, ty); + const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty); + return !needs_comptime; + }, + }; +} + fn explainWhyTypeIsComptime( sema: *Sema, block: *Block, @@ -20351,6 +20380,20 @@ pub fn resolveTypeFully( return resolveTypeFully(sema, block, src, ty.optionalChild(&buf)); }, .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()), + .Fn => { + const info = ty.fnInfo(); + if (info.is_generic) { + // Resolving of generic function types is defeerred to when + // the function is instantiated. + return; + } + for (info.param_types) |param_ty| { + const param_ty_src = src; // TODO better source location + try sema.resolveTypeFully(block, param_ty_src, param_ty); + } + const return_ty_src = src; // TODO better source location + try sema.resolveTypeFully(block, return_ty_src, info.return_type); + }, else => {}, } } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 43967ee0e5..bee68d675c 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -331,6 +331,7 @@ fn copy(src: *const u64, dst: *u64) void { } test "call result of if else expression" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 has different function pointers if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; @@ -341,7 +342,7 @@ test "call result of if else expression" { try expect(mem.eql(u8, f2(false), "b")); } fn f2(x: bool) []const u8 { - return (if (x) fA else fB)(); + return (if (x) &fA else &fB)(); } test "memcpy and memset intrinsics" { From c9b6f1bf907a0083f1fb0eba2f6969fd8f7f3b64 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 19 Mar 2022 14:05:57 +0200 Subject: [PATCH 2/3] std: enable default panic handler for stage2 LLVM on Linux --- lib/std/builtin.zig | 4 +- lib/std/debug.zig | 1 - lib/std/heap/general_purpose_allocator.zig | 4 +- lib/std/os/linux.zig | 49 ++++++++++++++++------ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index a6ef74dea0..8baeb2eb54 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -753,7 +753,9 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn @setCold(true); // Until self-hosted catches up with stage1 language features, we have a simpler // default panic function: - if (builtin.zig_backend != .stage1) { + const panic_works = builtin.zig_backend == .stage1 or + (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .linux); + if (!panic_works) { while (true) { @breakpoint(); } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index c50cdc2df8..4cae01ee6e 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1541,7 +1541,6 @@ pub const ModuleDebugInfo = switch (native_os) { .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???", .compile_unit_name = compile_unit.die.getAttrString(o_file_di, DW.AT.name) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => "???", - else => return err, }, .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o + addr_off) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, diff --git a/lib/std/heap/general_purpose_allocator.zig b/lib/std/heap/general_purpose_allocator.zig index 33d89e23c7..2519100e0d 100644 --- a/lib/std/heap/general_purpose_allocator.zig +++ b/lib/std/heap/general_purpose_allocator.zig @@ -341,7 +341,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index); const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc); const addr = bucket.page + slot_index * size_class; - if (builtin.zig_backend == .stage1) { + if (builtin.zig_backend == .stage1 or builtin.os.tag == .linux) { log.err("memory address 0x{x} leaked: {s}", .{ @ptrToInt(addr), stack_trace, }); @@ -379,7 +379,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { while (it.next()) |large_alloc| { if (config.retain_metadata and large_alloc.freed) continue; const stack_trace = large_alloc.getStackTrace(.alloc); - if (builtin.zig_backend == .stage1) { + if (builtin.zig_backend == .stage1 or builtin.os.tag == .linux) { log.err("memory address 0x{x} leaked: {s}", .{ @ptrToInt(large_alloc.bytes.ptr), stack_trace, }); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 7232bcfcd2..99c122075b 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1080,12 +1080,19 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact const mask_size = @sizeOf(@TypeOf(ksa.mask)); if (act) |new| { - const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) restore_rt else restore; + const restore_rt_ptr = if (builtin.zig_backend == .stage1) restore_rt else &syscall_bits.restore_rt; + // TODO https://github.com/ziglang/zig/issues/11227 + const restore_ptr = if (builtin.zig_backend == .stage1) restore else switch (native_arch) { + .arm, .thumb, .mips, .mipsel, .i386 => &syscall_bits.restore, + .x86_64, .aarch64, .riscv64, .sparcv9, .powerpc, .powerpc64, .powerpc64le => &syscall_bits.restore_rt, + else => unreachable, + }; + const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) restore_rt_ptr else restore_ptr; ksa = k_sigaction{ .handler = new.handler.handler, .flags = new.flags | SA.RESTORER, .mask = undefined, - .restorer = @ptrCast(fn () callconv(.C) void, restorer_fn), + .restorer = @ptrCast(k_sigaction_funcs.restorer, restorer_fn), }; @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &new.mask), mask_size); } @@ -3047,39 +3054,55 @@ pub const sigset_t = [1024 / 32]u32; pub const all_mask: sigset_t = [_]u32{0xffffffff} ** sigset_t.len; pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; +const k_sigaction_funcs = if (builtin.zig_backend == .stage1) struct { + const handler = ?fn (c_int) callconv(.C) void; + const restorer = fn () callconv(.C) void; +} else struct { + const handler = ?*const fn (c_int) callconv(.C) void; + const restorer = *const fn () callconv(.C) void; +}; + pub const k_sigaction = switch (native_arch) { .mips, .mipsel => extern struct { flags: c_uint, - handler: ?fn (c_int) callconv(.C) void, + handler: k_sigaction_funcs.handler, mask: [4]c_ulong, - restorer: fn () callconv(.C) void, + restorer: k_sigaction_funcs.restorer, }, .mips64, .mips64el => extern struct { flags: c_uint, - handler: ?fn (c_int) callconv(.C) void, + handler: k_sigaction_funcs.handler, mask: [2]c_ulong, - restorer: fn () callconv(.C) void, + restorer: k_sigaction_funcs.restorer, }, else => extern struct { - handler: ?fn (c_int) callconv(.C) void, + handler: k_sigaction_funcs.handler, flags: c_ulong, - restorer: fn () callconv(.C) void, + restorer: k_sigaction_funcs.restorer, mask: [2]c_uint, }, }; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = fn (c_int) callconv(.C) void; - pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + pub usingnamespace if (builtin.zig_backend == .stage1) struct { + pub const handler_fn = fn (c_int) callconv(.C) void; + pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + } else struct { + pub const handler_fn = *const fn (c_int) callconv(.C) void; + pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + }; handler: extern union { - handler: ?handler_fn, - sigaction: ?sigaction_fn, + handler: ?Sigaction.handler_fn, + sigaction: ?Sigaction.sigaction_fn, }, mask: sigset_t, flags: c_uint, - restorer: ?fn () callconv(.C) void = null, + restorer: ?if (builtin.zig_backend == .stage1) + fn () callconv(.C) void + else + *const fn () callconv(.C) void = null, }; pub const empty_sigset = [_]u32{0} ** @typeInfo(sigset_t).Array.len; From 12f3c461a4429d9c7a0ddbaa6465bf0499a99b8c Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 19 Mar 2022 15:13:27 +0200 Subject: [PATCH 3/3] Sema: implement zirSwitchCaptureElse for error sets --- lib/std/builtin.zig | 4 +-- lib/std/c/darwin.zig | 16 ++++++---- lib/std/heap/general_purpose_allocator.zig | 24 ++++----------- lib/std/macho.zig | 4 ++- src/Sema.zig | 34 ++++++++++++++++------ src/link/MachO.zig | 5 ++++ src/link/MachO/DebugSymbols.zig | 1 + src/value.zig | 32 ++++++++++++++++---- test/behavior/switch.zig | 6 +++- 9 files changed, 82 insertions(+), 44 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8baeb2eb54..4d69a624f9 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -753,9 +753,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn @setCold(true); // Until self-hosted catches up with stage1 language features, we have a simpler // default panic function: - const panic_works = builtin.zig_backend == .stage1 or - (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .linux); - if (!panic_works) { + if (builtin.zig_backend != .stage1 and builtin.zig_backend != .stage2_llvm) { while (true) { @breakpoint(); } diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index ec181c632f..b536471a30 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -624,8 +624,7 @@ pub const pthread_attr_t = extern struct { __opaque: [56]u8, }; -const pthread_t = std.c.pthread_t; -pub extern "c" fn pthread_threadid_np(thread: ?pthread_t, thread_id: *u64) c_int; +pub extern "c" fn pthread_threadid_np(thread: ?std.c.pthread_t, thread_id: *u64) c_int; pub extern "c" fn pthread_setname_np(name: [*:0]const u8) E; pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) E; @@ -921,12 +920,17 @@ pub const siginfo_t = extern struct { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. pub const Sigaction = extern struct { - pub const handler_fn = fn (c_int) callconv(.C) void; - pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + pub usingnamespace if (builtin.zig_backend == .stage1) struct { + pub const handler_fn = fn (c_int) callconv(.C) void; + pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + } else struct { + pub const handler_fn = *const fn (c_int) callconv(.C) void; + pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; + }; handler: extern union { - handler: ?handler_fn, - sigaction: ?sigaction_fn, + handler: ?Sigaction.handler_fn, + sigaction: ?Sigaction.sigaction_fn, }, mask: sigset_t, flags: c_uint, diff --git a/lib/std/heap/general_purpose_allocator.zig b/lib/std/heap/general_purpose_allocator.zig index 2519100e0d..7359fe402f 100644 --- a/lib/std/heap/general_purpose_allocator.zig +++ b/lib/std/heap/general_purpose_allocator.zig @@ -341,15 +341,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index); const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc); const addr = bucket.page + slot_index * size_class; - if (builtin.zig_backend == .stage1 or builtin.os.tag == .linux) { - log.err("memory address 0x{x} leaked: {s}", .{ - @ptrToInt(addr), stack_trace, - }); - } else { // TODO - log.err("memory address 0x{x} leaked", .{ - @ptrToInt(addr), - }); - } + log.err("memory address 0x{x} leaked: {s}", .{ + @ptrToInt(addr), stack_trace, + }); leaks = true; } if (bit_index == math.maxInt(u3)) @@ -379,15 +373,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { while (it.next()) |large_alloc| { if (config.retain_metadata and large_alloc.freed) continue; const stack_trace = large_alloc.getStackTrace(.alloc); - if (builtin.zig_backend == .stage1 or builtin.os.tag == .linux) { - log.err("memory address 0x{x} leaked: {s}", .{ - @ptrToInt(large_alloc.bytes.ptr), stack_trace, - }); - } else { // TODO - log.err("memory address 0x{x} leaked", .{ - @ptrToInt(large_alloc.bytes.ptr), - }); - } + log.err("memory address 0x{x} leaked: {s}", .{ + @ptrToInt(large_alloc.bytes.ptr), stack_trace, + }); leaks = true; } return leaks; diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 2e9ee4dfad..81d9bd0c47 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -624,7 +624,9 @@ pub const segment_command_64 = extern struct { cmd: LC = .SEGMENT_64, /// includes sizeof section_64 structs - cmdsize: u32 = @sizeOf(segment_command_64), + cmdsize: u32, + // TODO lazy values in stage2 + // cmdsize: u32 = @sizeOf(segment_command_64), /// segment name segname: [16]u8, diff --git a/src/Sema.zig b/src/Sema.zig index f8a5c28b80..94db6e80b9 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -131,6 +131,9 @@ pub const Block = struct { c_import_buf: ?*std.ArrayList(u8) = null, + /// type of `err` in `else => |err|` + switch_else_err_ty: ?Type = null, + const Param = struct { /// `noreturn` means `anytype`. ty: Type, @@ -189,6 +192,7 @@ pub const Block = struct { .runtime_index = parent.runtime_index, .want_safety = parent.want_safety, .c_import_buf = parent.c_import_buf, + .switch_else_err_ty = parent.switch_else_err_ty, }; } @@ -6714,12 +6718,6 @@ fn zirSwitchCapture( if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { // It is the else/`_` prong. - switch (operand_ty.zigTypeTag()) { - .ErrorSet => { - return sema.fail(block, operand_src, "TODO implement Sema for zirSwitchCaptureElse for error sets", .{}); - }, - else => {}, - } if (is_ref) { assert(operand_is_ref); return operand_ptr; @@ -6730,7 +6728,10 @@ fn zirSwitchCapture( else operand_ptr; - return operand; + switch (operand_ty.zigTypeTag()) { + .ErrorSet => return sema.bitCast(block, block.switch_else_err_ty.?, operand, operand_src), + else => return operand, + } } if (is_multi) { @@ -6907,6 +6908,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const operand_ty = sema.typeOf(operand); + var else_error_ty: ?Type = null; + // Validate usage of '_' prongs. if (special_prong == .under and !operand_ty.isNonexhaustiveEnum()) { const msg = msg: { @@ -7099,6 +7102,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .{}, ); } + else_error_ty = Type.@"anyerror"; } else { var maybe_msg: ?*Module.ErrorMsg = null; errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); @@ -7143,6 +7147,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .{}, ); } + + const error_names = operand_ty.errorSetNames(); + var names: Module.ErrorSet.NameMap = .{}; + try names.ensureUnusedCapacity(sema.arena, error_names.len); + for (error_names) |error_name| { + if (seen_errors.contains(error_name)) continue; + + names.putAssumeCapacityNoClobber(error_name, {}); + } + + else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); } }, .Union => return sema.fail(block, src, "TODO validate switch .Union", .{}), @@ -7420,6 +7435,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .label = &label, .inlining = block.inlining, .is_comptime = block.is_comptime, + .switch_else_err_ty = else_error_ty, }; const merges = &child_block.label.?.merges; defer child_block.instructions.deinit(gpa); @@ -18523,8 +18539,8 @@ pub fn bitCastVal( const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target)); const buffer = try sema.gpa.alloc(u8, abi_size); defer sema.gpa.free(buffer); - val.writeToMemory(old_ty, target, buffer); - return Value.readFromMemory(new_ty, target, buffer[buffer_offset..], sema.arena); + val.writeToMemory(old_ty, sema.mod, buffer); + return Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena); } fn coerceArrayPtrToSlice( diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 694ddc5613..1cab5fe067 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -4301,6 +4301,7 @@ fn populateMissingMetadata(self: *MachO) !void { .inner = .{ .segname = makeStaticString("__PAGEZERO"), .vmsize = pagezero_vmsize, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); @@ -4326,6 +4327,7 @@ fn populateMissingMetadata(self: *MachO) !void { .filesize = needed_size, .maxprot = macho.PROT.READ | macho.PROT.EXEC, .initprot = macho.PROT.READ | macho.PROT.EXEC, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); @@ -4431,6 +4433,7 @@ fn populateMissingMetadata(self: *MachO) !void { .filesize = needed_size, .maxprot = macho.PROT.READ | macho.PROT.WRITE, .initprot = macho.PROT.READ | macho.PROT.WRITE, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); @@ -4480,6 +4483,7 @@ fn populateMissingMetadata(self: *MachO) !void { .filesize = needed_size, .maxprot = macho.PROT.READ | macho.PROT.WRITE, .initprot = macho.PROT.READ | macho.PROT.WRITE, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); @@ -4589,6 +4593,7 @@ fn populateMissingMetadata(self: *MachO) !void { .fileoff = fileoff, .maxprot = macho.PROT.READ, .initprot = macho.PROT.READ, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 3d80e9a9b5..9fc2828ea1 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -148,6 +148,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void .vmsize = needed_size, .fileoff = fileoff, .filesize = needed_size, + .cmdsize = @sizeOf(macho.segment_command_64), }, }, }); diff --git a/src/value.zig b/src/value.zig index b45c106c26..8e6afccb60 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1042,7 +1042,8 @@ pub const Value = extern union { }; } - pub fn writeToMemory(val: Value, ty: Type, target: Target, buffer: []u8) void { + pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) void { + const target = mod.getTarget(); if (val.isUndef()) { const size = @intCast(usize, ty.abiSize(target)); std.mem.set(u8, buffer[0..size], 0xaa); @@ -1081,7 +1082,7 @@ pub const Value = extern union { var buf_off: usize = 0; while (elem_i < len) : (elem_i += 1) { const elem_val = val.elemValueBuffer(elem_i, &elem_value_buf); - writeToMemory(elem_val, elem_ty, target, buffer[buf_off..]); + writeToMemory(elem_val, elem_ty, mod, buffer[buf_off..]); buf_off += elem_size; } }, @@ -1092,7 +1093,7 @@ pub const Value = extern union { const field_vals = val.castTag(.aggregate).?.data; for (fields) |field, i| { const off = @intCast(usize, ty.structFieldOffset(i, target)); - writeToMemory(field_vals[i], field.ty, target, buffer[off..]); + writeToMemory(field_vals[i], field.ty, mod, buffer[off..]); } }, .Packed => { @@ -1105,6 +1106,12 @@ pub const Value = extern union { host_int.writeTwosComplement(buffer, bit_size, abi_size, target.cpu.arch.endian()); }, }, + .ErrorSet => { + // TODO revisit this when we have the concept of the error tag type + const Int = u16; + const int = mod.global_error_set.get(val.castTag(.@"error").?.data.name).?; + std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), target.cpu.arch.endian()); + }, else => @panic("TODO implement writeToMemory for more types"), } } @@ -1153,10 +1160,11 @@ pub const Value = extern union { pub fn readFromMemory( ty: Type, - target: Target, + mod: *Module, buffer: []const u8, arena: Allocator, ) Allocator.Error!Value { + const target = mod.getTarget(); switch (ty.zigTypeTag()) { .Int => { if (buffer.len == 0) return Value.zero; @@ -1184,7 +1192,7 @@ pub const Value = extern union { const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen())); var offset: usize = 0; for (elems) |*elem| { - elem.* = try readFromMemory(elem_ty, target, buffer[offset..], arena); + elem.* = try readFromMemory(elem_ty, mod, buffer[offset..], arena); offset += @intCast(usize, elem_size); } return Tag.aggregate.create(arena, elems); @@ -1196,7 +1204,7 @@ pub const Value = extern union { const field_vals = try arena.alloc(Value, fields.len); for (fields) |field, i| { const off = @intCast(usize, ty.structFieldOffset(i, target)); - field_vals[i] = try readFromMemory(field.ty, target, buffer[off..], arena); + field_vals[i] = try readFromMemory(field.ty, mod, buffer[off..], arena); } return Tag.aggregate.create(arena, field_vals); }, @@ -1212,6 +1220,18 @@ pub const Value = extern union { return intToPackedStruct(ty, target, bigint.toConst(), arena); }, }, + .ErrorSet => { + // TODO revisit this when we have the concept of the error tag type + const Int = u16; + const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], target.cpu.arch.endian()); + + const payload = try arena.create(Value.Payload.Error); + payload.* = .{ + .base = .{ .tag = .@"error" }, + .data = .{ .name = mod.error_name_list.items[@intCast(usize, int)] }, + }; + return Value.initPayload(&payload.base); + }, else => @panic("TODO implement readFromMemory for more types"), } } diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 5c47a24b38..ef9709b19a 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -430,7 +430,11 @@ test "switch on integer with else capturing expr" { } test "else prong of switch on error set excludes other cases" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void {