From 40cbf525f7d7b17b0728f835e6f68efe3c2eabf6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 17 Oct 2021 19:10:49 -0700 Subject: [PATCH] stage2: implement coercion from null to C pointer --- src/Sema.zig | 29 ++++++++++++++++++----------- src/value.zig | 1 + test/behavior/pointers.zig | 14 ++++++++++++++ test/behavior/pointers_stage1.zig | 14 -------------- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index c96b890785..589419be86 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4731,7 +4731,7 @@ fn zirFunc( body_inst, ret_ty_body, cc, - Value.initTag(.null_value), + Value.@"null", false, inferred_error_set, false, @@ -8105,7 +8105,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // return_type: ?type, field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); // args: []const FnArg, - field_values[5] = Value.initTag(.null_value); // TODO + field_values[5] = Value.@"null"; // TODO return sema.addConstant( type_info_ty, @@ -8163,7 +8163,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // is_allowzero: bool, field_values[5] = if (info.@"allowzero") Value.initTag(.bool_true) else Value.initTag(.bool_false); // sentinel: anytype, - field_values[6] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value); + field_values[6] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.@"null"; return sema.addConstant( type_info_ty, @@ -8181,7 +8181,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // child: type, field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); // sentinel: anytype, - field_values[2] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value); + field_values[2] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.@"null"; return sema.addConstant( type_info_ty, @@ -9753,7 +9753,7 @@ fn zirCmpxchg( // special case zero bit types if ((try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) != null) { - return sema.addConstant(result_ty, Value.initTag(.null_value)); + return sema.addConstant(result_ty, Value.@"null"); } const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { @@ -9767,7 +9767,7 @@ fn zirCmpxchg( const stored_val = (try ptr_val.pointerDeref(sema.arena)) orelse break :rs ptr_src; const result_val = if (stored_val.eql(expected_val, elem_ty)) blk: { try sema.storePtr(block, src, ptr, new_value); - break :blk Value.initTag(.null_value); + break :blk Value.@"null"; } else try Value.Tag.opt_payload.create(sema.arena, stored_val); return sema.addConstant(result_ty, result_val); @@ -10225,7 +10225,7 @@ fn zirVarExtended( // extra_index += 1; // const align_tv = try sema.resolveInstConst(block, align_src, align_ref); // break :blk align_tv.val; - //} else Value.initTag(.null_value); + //} else Value.@"null"; const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: { const init_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); @@ -10307,7 +10307,7 @@ fn zirFuncExtended( extra_index += 1; const align_tv = try sema.resolveInstConst(block, align_src, align_ref); break :blk align_tv.val; - } else Value.initTag(.null_value); + } else Value.@"null"; const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -10592,7 +10592,7 @@ fn panicWithMsg( }); const null_stack_trace = try sema.addConstant( try Type.optional(arena, ptr_stack_trace_ty), - Value.initTag(.null_value), + Value.@"null", ); const args = try arena.create([2]Air.Inst.Ref); args.* = .{ msg_inst, null_stack_trace }; @@ -11544,7 +11544,7 @@ fn coerce( .Optional => { // null to ?T if (inst_ty.zigTypeTag() == .Null) { - return sema.addConstant(dest_ty, Value.initTag(.null_value)); + return sema.addConstant(dest_ty, Value.@"null"); } // T to ?T @@ -11605,6 +11605,13 @@ fn coerce( .One => {}, } } + + // coercion to C pointer + if (dest_ty.ptrSize() == .C) { + if (inst_ty.zigTypeTag() == .Null) { + return sema.addConstant(dest_ty, Value.@"null"); + } + } }, .Int => { // integer widening @@ -13806,7 +13813,7 @@ fn typeHasOnePossibleValue( .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), .void => return Value.void, .noreturn => return Value.initTag(.unreachable_value), - .@"null" => return Value.initTag(.null_value), + .@"null" => return Value.@"null", .@"undefined" => return Value.initTag(.undef), .int_unsigned, .int_signed => { diff --git a/src/value.zig b/src/value.zig index 030ee8f783..1ae5351f54 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2824,6 +2824,7 @@ pub const Value = extern union { pub const negative_one: Value = .{ .ptr_otherwise = &negative_one_payload.base }; pub const undef = initTag(.undef); pub const @"void" = initTag(.void_value); + pub const @"null" = initTag(.null_value); }; var negative_one_payload: Value.Payload.I64 = .{ diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 4fcd78b1d6..47d21b8155 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -44,3 +44,17 @@ test "double pointer parsing" { fn PtrOf(comptime T: type) type { return *T; } + +test "implicit cast single item pointer to C pointer and back" { + var y: u8 = 11; + var x: [*c]u8 = &y; + var z: *u8 = x; + z.* += 1; + try expect(y == 12); +} + +test "initialize const optional C pointer to null" { + const a: ?[*c]i32 = null; + try expect(a == null); + comptime try expect(a == null); +} diff --git a/test/behavior/pointers_stage1.zig b/test/behavior/pointers_stage1.zig index aea123a5c3..7515559606 100644 --- a/test/behavior/pointers_stage1.zig +++ b/test/behavior/pointers_stage1.zig @@ -29,14 +29,6 @@ test "assigning integer to C pointer" { } } -test "implicit cast single item pointer to C pointer and back" { - var y: u8 = 11; - var x: [*c]u8 = &y; - var z: *u8 = x; - z.* += 1; - try expect(y == 12); -} - test "C pointer comparison and arithmetic" { const S = struct { fn doTheTest() !void { @@ -103,12 +95,6 @@ test "implicit cast error unions with non-optional to optional pointer" { comptime try S.doTheTest(); } -test "initialize const optional C pointer to null" { - const a: ?[*c]i32 = null; - try expect(a == null); - comptime try expect(a == null); -} - test "compare equality of optional and non-optional pointer" { const a = @intToPtr(*const usize, 0x12345678); const b = @intToPtr(?*usize, 0x12345678);