From 25874747174da2b0e77b3b888d0f5a13aa1a317e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Apr 2022 10:12:45 -0700 Subject: [PATCH] stage2: progress towards stage3 * The `@bitCast` workaround is removed in favor of `@ptrCast` properly doing element casting for slice element types. This required an enhancement both to stage1 and stage2. * stage1 incorrectly accepts `.{}` instead of `{}`. stage2 code that abused this is fixed. * Make some parameters comptime to support functions in switch expressions (as opposed to making them function pointers). * Avoid relying on local temporaries being mutable. * Workarounds for when stage1 and stage2 disagree on function pointer types. * Workaround recursive formatting bug with a `@panic("TODO")`. * Remove unreachable `else` prongs for some inferred error sets. All in effort towards #89. --- lib/std/fmt.zig | 2 -- lib/std/io.zig | 1 - lib/std/rand.zig | 4 +--- src/AstGen.zig | 4 ++-- src/Liveness.zig | 8 ++++---- src/Module.zig | 4 ++-- src/Sema.zig | 34 +++++++++++++++++++++++++--------- src/arch/aarch64/CodeGen.zig | 13 ++++++++----- src/arch/arm/CodeGen.zig | 13 ++++++++----- src/arch/arm/Emit.zig | 25 ++++++++++++++++++------- src/arch/riscv64/CodeGen.zig | 8 ++++---- src/arch/wasm/CodeGen.zig | 4 ++-- src/arch/x86_64/CodeGen.zig | 22 ++++++++++++++-------- src/codegen/c.zig | 17 ++++++++--------- src/codegen/llvm.zig | 10 +++++----- src/link.zig | 7 ++++++- src/link/C.zig | 5 +++-- src/link/Elf.zig | 2 +- src/link/MachO/Object.zig | 1 - src/link/MachO/fat.zig | 1 - src/link/Plan9.zig | 2 +- src/link/Wasm.zig | 26 ++++++++++++++++---------- src/print_air.zig | 10 +++++----- src/stage1/ir.cpp | 6 ++++++ src/type.zig | 2 +- test/behavior/ptrcast.zig | 16 ++++++++++++++++ 26 files changed, 156 insertions(+), 91 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 03395c024c..3f230a445e 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -766,12 +766,10 @@ fn formatFloatValue( } else if (comptime std.mem.eql(u8, fmt, "d")) { formatFloatDecimal(value, options, buf_stream.writer()) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; } else if (comptime std.mem.eql(u8, fmt, "x")) { formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; } else { @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); diff --git a/lib/std/io.zig b/lib/std/io.zig index fba1c289f7..50d134b856 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -9,7 +9,6 @@ const os = std.os; const fs = std.fs; const mem = std.mem; const meta = std.meta; -const trait = meta.trait; const File = std.fs.File; pub const Mode = enum { diff --git a/lib/std/rand.zig b/lib/std/rand.zig index cfac15a1fb..0c3a0fd2ba 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -66,9 +66,7 @@ pub const Random = struct { /// Returns a random value from an enum, evenly distributed. pub fn enumValue(r: Random, comptime EnumType: type) EnumType { - if (comptime !std.meta.trait.is(.Enum)(EnumType)) { - @compileError("Random.enumValue requires an enum type, not a " ++ @typeName(EnumType)); - } + comptime assert(@typeInfo(EnumType) == .Enum); // We won't use int -> enum casting because enum elements can have // arbitrary values. Instead we'll randomly pick one of the type's values. diff --git a/src/AstGen.zig b/src/AstGen.zig index 75882c761b..ccce4b0bc8 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -85,12 +85,12 @@ fn reserveExtra(astgen: *AstGen, size: usize) Allocator.Error!u32 { } fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { - const coerced = @bitCast([]const u32, refs); + const coerced = @ptrCast([]const u32, refs); return astgen.extra.appendSlice(astgen.gpa, coerced); } fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { - const coerced = @bitCast([]const u32, refs); + const coerced = @ptrCast([]const u32, refs); astgen.extra.appendSliceAssumeCapacity(coerced); } diff --git a/src/Liveness.zig b/src/Liveness.zig index d63c442482..be4344ab90 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -454,7 +454,7 @@ fn analyzeInst( const inst_data = inst_datas[inst].pl_op; const callee = inst_data.operand; const extra = a.air.extraData(Air.Call, inst_data.payload); - const args = @bitCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..extra.data.args_len]); if (args.len + 1 <= bpi - 1) { var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1); buf[0] = callee; @@ -495,7 +495,7 @@ fn analyzeInst( const ty_pl = inst_datas[inst].ty_pl; const aggregate_ty = a.air.getRefType(ty_pl.ty); const len = @intCast(usize, aggregate_ty.arrayLen()); - const elements = @bitCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]); if (elements.len <= bpi - 1) { var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1); @@ -571,9 +571,9 @@ fn analyzeInst( .assembly => { const extra = a.air.extraData(Air.Asm, inst_datas[inst].ty_pl.payload); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; simple: { diff --git a/src/Module.zig b/src/Module.zig index 83252c76ad..53c72ccec2 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4593,7 +4593,7 @@ pub fn clearDecl( .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, - .nvptx => .{ .nvptx = .{} }, + .nvptx => .{ .nvptx = {} }, }; } if (decl.getInnerNamespace()) |namespace| { @@ -4975,7 +4975,7 @@ pub fn allocateNewDecl( .c => .{ .c = {} }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .spirv => .{ .spirv = .{} }, - .nvptx => .{ .nvptx = .{} }, + .nvptx => .{ .nvptx = {} }, }, .generation = 0, .is_pub = false, diff --git a/src/Sema.zig b/src/Sema.zig index 97fe3cb595..e00abd660b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14110,21 +14110,27 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air try sema.checkPtrType(block, dest_ty_src, dest_ty); try sema.checkPtrOperand(block, operand_src, operand_ty); - if (dest_ty.isSlice()) { + + const dest_is_slice = dest_ty.isSlice(); + const operand_is_slice = operand_ty.isSlice(); + if (dest_is_slice and !operand_is_slice) { return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{}); } - const ptr = if (operand_ty.isSlice()) + const ptr = if (operand_is_slice and !dest_is_slice) try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty) else operand; - try sema.resolveTypeLayout(block, dest_ty_src, dest_ty.elemType2()); + const dest_elem_ty = dest_ty.elemType2(); + try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty); const dest_align = dest_ty.ptrAlignment(target); - try sema.resolveTypeLayout(block, operand_src, operand_ty.elemType2()); + + const operand_elem_ty = operand_ty.elemType2(); + try sema.resolveTypeLayout(block, operand_src, operand_elem_ty); const operand_align = operand_ty.ptrAlignment(target); // If the destination is less aligned than the source, preserve the source alignment - var aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { + const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result if (dest_ty.zigTypeTag() == .Optional) { var buf: Type.Payload.ElemType = undefined; @@ -14138,6 +14144,16 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } }; + if (dest_is_slice) { + const operand_elem_size = operand_elem_ty.abiSize(target); + const dest_elem_size = dest_elem_ty.abiSize(target); + if (operand_elem_size != dest_elem_size) { + // note that this is not implemented in stage1 so we should probably wait + // until that codebase is replaced before implementing this in stage2. + return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{}); + } + } + return sema.coerceCompatiblePtrs(block, aligned_dest_ty, ptr, operand_src); } @@ -15743,7 +15759,7 @@ fn zirMinMax( sema: *Sema, block: *Block, inst: Zir.Inst.Index, - air_tag: Air.Inst.Tag, + comptime air_tag: Air.Inst.Tag, ) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; @@ -15763,7 +15779,7 @@ fn analyzeMinMax( src: LazySrcLoc, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, - air_tag: Air.Inst.Tag, + comptime air_tag: Air.Inst.Tag, lhs_src: LazySrcLoc, rhs_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { @@ -20976,7 +20992,7 @@ fn resolvePeerTypes( sema: *Sema, block: *Block, src: LazySrcLoc, - instructions: []Air.Inst.Ref, + instructions: []const Air.Inst.Ref, candidate_srcs: Module.PeerTypeCandidateSrc, ) !Type { switch (instructions.len) { @@ -22794,7 +22810,7 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 { } fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void { - const coerced = @bitCast([]const u32, refs); + const coerced = @ptrCast([]const u32, refs); sema.air_extra.appendSliceAssumeCapacity(coerced); } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 0aac47c6c5..95d2a8a607 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -2398,7 +2398,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. const pl_op = self.air.instructions.items(.data)[inst].pl_op; const callee = pl_op.operand; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); const ty = self.air.typeOf(callee); const fn_ty = switch (ty.zigTypeTag()) { @@ -2865,7 +2865,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { // TODO track the new register / stack allocation } - self.branch_stack.pop().deinit(self.gpa); + { + var item = self.branch_stack.pop(); + item.deinit(self.gpa); + } // We already took care of pl_op.operand earlier, so we're going // to pass .none here @@ -3162,9 +3165,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); @@ -3686,7 +3689,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { const vector_ty = self.air.typeOfIndex(inst); const len = vector_ty.vectorLen(); const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); const result: MCValue = res: { if (self.liveness.isUnused(inst)) break :res MCValue.dead; return self.fail("TODO implement airAggregateInit for {}", .{self.target.cpu.arch}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 27f048999b..f71ceaba89 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -3144,7 +3144,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. const pl_op = self.air.instructions.items(.data)[inst].pl_op; const callee = pl_op.operand; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); const ty = self.air.typeOf(callee); const fn_ty = switch (ty.zigTypeTag()) { @@ -3650,7 +3650,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { // TODO track the new register / stack allocation } - self.branch_stack.pop().deinit(self.gpa); + { + var item = self.branch_stack.pop(); + item.deinit(self.gpa); + } // We already took care of pl_op.operand earlier, so we're going // to pass .none here @@ -3951,9 +3954,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); @@ -4735,7 +4738,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { const vector_ty = self.air.typeOfIndex(inst); const len = vector_ty.vectorLen(); const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); const result: MCValue = res: { if (self.liveness.isUnused(inst)) break :res MCValue.dead; return self.fail("TODO implement airAggregateInit for arm", .{}); diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 7c9e508e5f..209ab137a6 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -2,6 +2,7 @@ //! machine code const Emit = @This(); +const builtin = @import("builtin"); const std = @import("std"); const math = std.math; const Mir = @import("Mir.zig"); @@ -622,12 +623,17 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { } else return emit.fail("TODO mirLoadStack larger offsets", .{}); const ldr = switch (tag) { - .ldr_stack_argument => Instruction.ldr, - .ldrb_stack_argument => Instruction.ldrb, + .ldr_stack_argument => &Instruction.ldr, + .ldrb_stack_argument => &Instruction.ldrb, else => unreachable, }; - try emit.writeInstruction(ldr( + const ldr_workaround = switch (builtin.zig_backend) { + .stage1 => ldr.*, + else => ldr, + }; + + try emit.writeInstruction(ldr_workaround( cond, r_stack_offset.rt, .fp, @@ -643,13 +649,18 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { } else return emit.fail("TODO mirLoadStack larger offsets", .{}); const ldr = switch (tag) { - .ldrh_stack_argument => Instruction.ldrh, - .ldrsb_stack_argument => Instruction.ldrsb, - .ldrsh_stack_argument => Instruction.ldrsh, + .ldrh_stack_argument => &Instruction.ldrh, + .ldrsb_stack_argument => &Instruction.ldrsb, + .ldrsh_stack_argument => &Instruction.ldrsh, else => unreachable, }; - try emit.writeInstruction(ldr( + const ldr_workaround = switch (builtin.zig_backend) { + .stage1 => ldr.*, + else => ldr, + }; + + try emit.writeInstruction(ldr_workaround( cond, r_stack_offset.rt, .fp, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 25a7a65f57..cf9e5fefcd 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1640,7 +1640,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. const fn_ty = self.air.typeOf(pl_op.operand); const callee = pl_op.operand; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); var info = try self.resolveCallingConventionValues(fn_ty); defer info.deinit(self); @@ -2075,9 +2075,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); @@ -2413,7 +2413,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { const vector_ty = self.air.typeOfIndex(inst); const len = vector_ty.vectorLen(); const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); const result: MCValue = res: { if (self.liveness.isUnused(inst)) break :res MCValue.dead; return self.fail("TODO implement airAggregateInit for riscv64", .{}); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 38ab19cb60..b701299e73 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2425,7 +2425,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { var highest_maybe: ?i32 = null; while (case_i < switch_br.data.cases_len) : (case_i += 1) { const case = self.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); + const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + items.len + case_body.len; const values = try self.gpa.alloc(CaseValue, items.len); @@ -3328,7 +3328,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const result_ty = self.air.typeOfIndex(inst); const len = @intCast(usize, result_ty.arrayLen()); - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); switch (result_ty.zigTypeTag()) { .Vector => return self.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}), diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 53a6bfc4d9..10271df122 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -3501,7 +3501,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. const pl_op = self.air.instructions.items(.data)[inst].pl_op; const callee = pl_op.operand; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); const ty = self.air.typeOf(callee); const fn_ty = switch (ty.zigTypeTag()) { @@ -3684,7 +3684,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. .ops = (Mir.Ops{ .flags = 0b01, }).encode(), - .data = .{ .imm = @bitCast(i32, @intCast(u32, fn_got_addr)) }, + .data = .{ .imm = @intCast(u32, fn_got_addr) }, }); } else return self.fail("TODO implement calling extern fn on plan9", .{}); } else { @@ -4220,7 +4220,10 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { // TODO track the new register / stack allocation } - self.branch_stack.pop().deinit(self.gpa); + { + var item = self.branch_stack.pop(); + item.deinit(self.gpa); + } // We already took care of pl_op.operand earlier, so we're going // to pass .none here @@ -4562,7 +4565,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { while (case_i < switch_br.data.cases_len) : (case_i += 1) { const case = self.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); + const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + items.len + case_body.len; @@ -4615,7 +4618,10 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { if (switch_br.data.else_body_len > 0) { const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; try self.branch_stack.append(.{}); - defer self.branch_stack.pop().deinit(self.gpa); + defer { + var item = self.branch_stack.pop(); + item.deinit(self.gpa); + } const else_deaths = liveness.deaths.len - 1; try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len); @@ -4705,9 +4711,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); @@ -5975,7 +5981,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { const result_ty = self.air.typeOfIndex(inst); const len = @intCast(usize, result_ty.arrayLen()); const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); const abi_align = result_ty.abiAlignment(self.target.*); const result: MCValue = res: { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 69288494bc..54f8285291 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -220,6 +220,9 @@ fn formatIdent( } pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { + if (builtin.zig_backend != .stage1) { + @panic("TODO"); + } return .{ .data = ident }; } @@ -2310,7 +2313,6 @@ fn airWrapOp( const val = -1 * std.math.pow(i64, 2, @intCast(i64, bits - 1)); break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; }, }, @@ -2336,7 +2338,6 @@ fn airWrapOp( const val = std.math.pow(u64, 2, pow_bits) - 1; break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; }, }; @@ -2418,7 +2419,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { const val = -1 * std.math.pow(i65, 2, @intCast(i65, bits - 1)); break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; }, }, @@ -2444,7 +2444,6 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { const val = std.math.pow(u65, 2, pow_bits) - 1; break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, - else => |e| return e, }; }, }; @@ -2702,7 +2701,7 @@ fn airCall( } const pl_op = f.air.instructions.items(.data)[inst].pl_op; const extra = f.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); const callee_ty = f.air.typeOf(pl_op.operand); const fn_ty = switch (callee_ty.zigTypeTag()) { .Fn => callee_ty, @@ -2959,7 +2958,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { var case_i: u32 = 0; while (case_i < switch_br.data.cases_len) : (case_i += 1) { const case = f.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]); + const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]); const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + case.data.items_len + case_body.len; @@ -2990,9 +2989,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none; @@ -3860,7 +3859,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const vector_ty = f.air.getRefType(ty_pl.ty); const len = vector_ty.vectorLen(); - const elements = @bitCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index db4c08f86f..f55d326a47 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3657,7 +3657,7 @@ pub const FuncGen = struct { fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*const llvm.Value { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); const callee_ty = self.air.typeOf(pl_op.operand); const zig_fn_ty = switch (callee_ty.zigTypeTag()) { .Fn => callee_ty, @@ -4037,7 +4037,7 @@ pub const FuncGen = struct { while (case_i < switch_br.data.cases_len) : (case_i += 1) { const case = self.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); + const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + case.data.items_len + case_body.len; @@ -4538,9 +4538,9 @@ pub const FuncGen = struct { if (!is_volatile and self.liveness.isUnused(inst)) return null; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; if (outputs.len > 1) { @@ -6660,7 +6660,7 @@ pub const FuncGen = struct { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const result_ty = self.air.typeOfIndex(inst); const len = @intCast(usize, result_ty.arrayLen()); - const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); const llvm_result_ty = try self.dg.llvmType(result_ty); const target = self.dg.module.getTarget(); diff --git a/src/link.zig b/src/link.zig index 139b12af99..dbef400189 100644 --- a/src/link.zig +++ b/src/link.zig @@ -649,6 +649,11 @@ pub const File = struct { } } + pub const UpdateDeclExportsError = error{ + OutOfMemory, + AnalysisFail, + }; + /// May be called before or after updateDecl, but must be called after /// allocateDeclIndexes for any given Decl. pub fn updateDeclExports( @@ -656,7 +661,7 @@ pub const File = struct { module: *Module, decl: *Module.Decl, exports: []const *Module.Export, - ) !void { + ) UpdateDeclExportsError!void { log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); assert(decl.has_tv); switch (base.tag) { diff --git a/src/link/C.zig b/src/link/C.zig index 85b7c24487..229990fc8e 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -89,8 +89,9 @@ pub fn deinit(self: *C) void { pub fn freeDecl(self: *C, decl: *Module.Decl) void { const gpa = self.base.allocator; - if (self.decl_table.fetchSwapRemove(decl)) |*kv| { - kv.value.deinit(gpa); + if (self.decl_table.fetchSwapRemove(decl)) |kv| { + var decl_block = kv.value; + decl_block.deinit(gpa); } } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 9e1ed0cf54..4ae7ab64a4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2482,7 +2482,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ - .none = .{}, + .none = {}, }, .{ .parent_atom_index = atom.local_sym_index, }); diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 6620c99b49..255d7053d4 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -625,7 +625,6 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { while (true) { const dice = reader.readStruct(macho.data_in_code_entry) catch |err| switch (err) { error.EndOfStream => break, - else => |e| return e, }; try self.data_in_code_entries.append(allocator, dice); } diff --git a/src/link/MachO/fat.zig b/src/link/MachO/fat.zig index 89a2272dd1..1f8a6a2e84 100644 --- a/src/link/MachO/fat.zig +++ b/src/link/MachO/fat.zig @@ -40,7 +40,6 @@ pub fn getLibraryOffset(reader: anytype, target: std.Target) !u64 { // fine because we can keep looking for one that might match. const lib_arch = decodeArch(fat_arch.cputype, false) catch |err| switch (err) { error.UnsupportedCpuArchitecture => continue, - else => |e| return e, }; if (lib_arch == target.cpu.arch) { // We have found a matching architecture! diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 8096b2d38c..3269cb67d4 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -307,7 +307,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, - }, &code_buffer, .{ .none = .{} }, .{ + }, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = @intCast(u32, sym_index), }); const code = switch (res) { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index c717b42bb6..ffd3eef7b6 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2551,7 +2551,8 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * .iov_base = payload.items.ptr, .iov_len = payload.items.len, }; - try file.writevAll(&.{iovec}); + var iovecs = [_]std.os.iovec_const{iovec}; + try file.writevAll(&iovecs); } fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { @@ -2576,7 +2577,8 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { .iov_base = payload.items.ptr, .iov_len = payload.items.len, }; - try file.writevAll(&.{iovec}); + var iovecs = [_]std.os.iovec_const{iovec}; + try file.writevAll(&iovecs); } fn getULEB128Size(uint_value: anytype) u32 { @@ -2635,12 +2637,14 @@ fn emitCodeRelocations( var buf: [5]u8 = undefined; leb.writeUnsignedFixed(5, &buf, count); try payload.insertSlice(reloc_start, &buf); - const iovec: std.os.iovec_const = .{ - .iov_base = payload.items.ptr, - .iov_len = payload.items.len, + var iovecs = [_]std.os.iovec_const{ + .{ + .iov_base = payload.items.ptr, + .iov_len = payload.items.len, + }, }; const header_offset = try reserveCustomSectionHeader(file); - try file.writevAll(&.{iovec}); + try file.writevAll(&iovecs); const size = @intCast(u32, payload.items.len); try writeCustomSectionHeader(file, header_offset, size); } @@ -2694,12 +2698,14 @@ fn emitDataRelocations( var buf: [5]u8 = undefined; leb.writeUnsignedFixed(5, &buf, count); try payload.insertSlice(reloc_start, &buf); - const iovec: std.os.iovec_const = .{ - .iov_base = payload.items.ptr, - .iov_len = payload.items.len, + var iovecs = [_]std.os.iovec_const{ + .{ + .iov_base = payload.items.ptr, + .iov_len = payload.items.len, + }, }; const header_offset = try reserveCustomSectionHeader(file); - try file.writevAll(&.{iovec}); + try file.writevAll(&iovecs); const size = @intCast(u32, payload.items.len); try writeCustomSectionHeader(file, header_offset, size); } diff --git a/src/print_air.zig b/src/print_air.zig index 82583a3c55..8a1a8fa950 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -328,7 +328,7 @@ const Writer = struct { const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; const vector_ty = w.air.getRefType(ty_pl.ty); const len = @intCast(usize, vector_ty.arrayLen()); - const elements = @bitCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); + const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); try s.print("{}, [", .{vector_ty.fmtDebug()}); for (elements) |elem, i| { @@ -533,9 +533,9 @@ const Writer = struct { try s.writeAll(", volatile"); } - const outputs = @bitCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; for (outputs) |output| { @@ -604,7 +604,7 @@ const Writer = struct { fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const pl_op = w.air.instructions.items(.data)[inst].pl_op; const extra = w.air.extraData(Air.Call, pl_op.payload); - const args = @bitCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]); + const args = @ptrCast([]const Air.Inst.Ref, w.air.extra[extra.end..][0..extra.data.args_len]); try w.writeOperand(s, inst, 0, pl_op.operand); try s.writeAll(", ["); for (args) |arg, i| { @@ -674,7 +674,7 @@ const Writer = struct { while (case_i < switch_br.data.cases_len) : (case_i += 1) { const case = w.air.extraData(Air.SwitchBr.Case, extra_index); - const items = @bitCast([]const Air.Inst.Ref, w.air.extra[case.end..][0..case.data.items_len]); + const items = @ptrCast([]const Air.Inst.Ref, w.air.extra[case.end..][0..case.data.items_len]); const case_body = w.air.extra[case.end + items.len ..][0..case.data.body_len]; extra_index = case.end + case.data.items_len + case_body.len; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 11f47c592b..c3157b6539 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -23052,6 +23052,12 @@ static Stage1AirInst *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, Stage1ZirI if (type_is_invalid(src_type)) return ira->codegen->invalid_inst_gen; + // This logic is not quite right; this is just to get stage1 to accept valid code + // we use in the self-hosted compiler. + if (is_slice(dest_type) && is_slice(src_type)) { + return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, dest_type); + } + bool keep_bigger_alignment = true; return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, instruction->ptr->source_node, dest_type, dest_type_value->source_node, diff --git a/src/type.zig b/src/type.zig index da0149967b..2a19f7375b 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1451,7 +1451,7 @@ pub const Type = extern union { var duped_names = Module.ErrorSet.NameMap{}; try duped_names.ensureTotalCapacity(allocator, names.len); for (names) |name| { - duped_names.putAssumeCapacityNoClobber(name, .{}); + duped_names.putAssumeCapacityNoClobber(name, {}); } return Tag.error_set_merged.create(allocator, duped_names); }, diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index d9a3892664..10138cff01 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -217,3 +217,19 @@ test "implicit optional pointer to optional anyopaque pointer" { var z = @ptrCast(*[4]u8, y); try expect(std.mem.eql(u8, z, "aoeu")); } + +test "@ptrCast slice to slice" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + fn foo(slice: []u32) []i32 { + return @ptrCast([]i32, slice); + } + }; + var buf: [4]u32 = .{ 0, 0, 0, 0 }; + const alias = S.foo(&buf); + alias[1] = 42; + try expect(buf[1] == 42); + try expect(alias.len == 4); +}