diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index d0639463a0..dfc2020334 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -32,10 +32,8 @@ comptime { @export(wasm_start, .{ .name = "_start", .linkage = .Strong }); } - if (builtin.zig_backend == .stage1) { // TODO remove this condition - if (native_os == .linux) { - @export(clone, .{ .name = "clone" }); - } + if (native_os == .linux) { + @export(clone, .{ .name = "clone" }); } @export(memset, .{ .name = "memset", .linkage = .Strong }); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a9e1cb160b..bb7554d363 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4732,10 +4732,11 @@ pub const FuncGen = struct { var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; if (invert) { - return self.builder.buildNot(operand, ""); + return self.builder.buildNot(loaded, ""); } else { - return operand; + return loaded; } } @@ -4784,12 +4785,16 @@ pub const FuncGen = struct { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.air.typeOf(ty_op.operand).childType(); + const result_ty = self.air.getRefType(ty_op.ty); var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { // We have a pointer to a zero-bit value and we need to return // a pointer to a zero-bit value. - return operand; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); } if (optional_ty.isPtrLikeOptional()) { // The payload and the optional are the same value. @@ -4807,13 +4812,17 @@ pub const FuncGen = struct { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.air.typeOf(ty_op.operand).childType(); + const result_ty = self.air.getRefType(ty_op.ty); var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); const non_null_bit = self.context.intType(1).constAllOnes(); if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { // We have a pointer to a i1. We need to set it to 1 and then return the same pointer. _ = self.builder.buildStore(non_null_bit, operand); - return operand; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); } if (optional_ty.isPtrLikeOptional()) { // The payload and the optional are the same value. @@ -4872,7 +4881,13 @@ pub const FuncGen = struct { const target = self.dg.module.getTarget(); const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1; - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null; + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + if (!operand_is_ptr) return null; + + // TODO once we update to LLVM 14 this bitcast won't be necessary. + const res_ptr_ty = try self.dg.llvmType(result_ty); + return self.builder.buildBitCast(operand, res_ptr_ty, ""); + } if (operand_is_ptr or isByRef(payload_ty)) { return self.builder.buildStructGEP(operand, offset, ""); } diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 9956c3f3ec..6219a6a5be 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -332,3 +332,42 @@ test "array of optional unaligned types" { i += 1; try expect(Enum.three == values[i].?.Num); } + +test "optional pointer to zero bit optional payload" { + if (builtin.zig_backend == .stage2_c) 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 + + const B = struct { + fn foo(_: *@This()) void {} + }; + const A = struct { + b: ?B = .{}, + }; + var a: A = .{}; + var a_ptr = &a; + if (a_ptr.b) |*some| { + some.foo(); + } +} + +test "optional pointer to zero bit error union payload" { + if (builtin.zig_backend == .stage2_c) 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_wasm) return error.SkipZigTest; // TODO + + const B = struct { + fn foo(_: *@This()) void {} + }; + const A = struct { + b: anyerror!B = .{}, + }; + var a: A = .{}; + var a_ptr = &a; + if (a_ptr.b) |*some| { + some.foo(); + } else |_| {} +}