authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-22 20:47:40-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-22 20:47:40-07:00
logf591936480730a279d55a051f92806e19834faf7
treedda39b1ee5d5e8cb1d9cc222a19188cabcb1329f
parenteb1b2f5c58888bfcab7e00378502f82594536aec
parent423a19fa60d2b0a11fc2fb43b12001320c2c53c5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12198 from Vexu/stage2

Sema: fix loading and storing of optional pointers represented as pointers

7 files changed, 145 insertions(+), 18 deletions(-)

src/Sema.zig+47-15
......@@ -1663,11 +1663,15 @@ fn resolveMaybeUndefValIntable(
16631663 inst: Air.Inst.Ref,
16641664) CompileError!?Value {
16651665 const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
1666 switch (val.tag()) {
1667 .variable, .decl_ref, .decl_ref_mut => return null,
1666 var check = val;
1667 while (true) switch (check.tag()) {
1668 .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
1669 .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
1670 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
1671 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
16681672 .generic_poison => return error.GenericPoison,
16691673 else => return val,
1670 }
1674 };
16711675}
16721676
16731677/// Returns all Value tags including `variable` and `undef`.
......@@ -3871,9 +3875,15 @@ fn zirValidateArrayInit(
38713875 const array_len = array_ty.arrayLen();
38723876
38733877 if (instrs.len != array_len) {
3874 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
3875 array_len, instrs.len,
3876 });
3878 if (array_ty.zigTypeTag() == .Array) {
3879 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
3880 array_len, instrs.len,
3881 });
3882 } else {
3883 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
3884 array_len, instrs.len,
3885 });
3886 }
38773887 }
38783888
38793889 if ((is_comptime or block.is_comptime) and
......@@ -7893,7 +7903,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
78937903 if (!ptr_ty.isPtrAtRuntime()) {
78947904 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)});
78957905 }
7896 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
7906 if (try sema.resolveMaybeUndefValIntable(block, ptr_src, ptr)) |ptr_val| {
78977907 return sema.addConstant(Type.usize, ptr_val);
78987908 }
78997909 try sema.requireRuntimeBlock(block, ptr_src, ptr_src);
......@@ -14261,7 +14271,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1426114271
1426214272 switch (obj_ty.zigTypeTag()) {
1426314273 .Struct => return sema.structInitEmpty(block, obj_ty, src, src),
14264 .Array => return arrayInitEmpty(sema, obj_ty),
14274 .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty),
1426514275 .Void => return sema.addConstant(obj_ty, Value.void),
1426614276 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
1426714277 }
......@@ -14286,7 +14296,15 @@ fn structInitEmpty(
1428614296 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
1428714297}
1428814298
14289fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
14299fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
14300 const arr_len = obj_ty.arrayLen();
14301 if (arr_len != 0) {
14302 if (obj_ty.zigTypeTag() == .Array) {
14303 return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len});
14304 } else {
14305 return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len});
14306 }
14307 }
1429014308 if (obj_ty.sentinel()) |sentinel| {
1429114309 const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel);
1429214310 return sema.addConstant(obj_ty, val);
......@@ -19448,7 +19466,7 @@ fn fieldCallBind(
1944819466
1944919467 const raw_ptr_src = src; // TODO better source location
1945019468 const raw_ptr_ty = sema.typeOf(raw_ptr);
19451 const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and raw_ptr_ty.ptrSize() == .One)
19469 const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C))
1945219470 raw_ptr_ty.childType()
1945319471 else
1945419472 return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)});
......@@ -20974,7 +20992,7 @@ fn coerceExtra(
2097420992 .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
2097520993 .Struct => {
2097620994 if (inst == .empty_struct) {
20977 return arrayInitEmpty(sema, dest_ty);
20995 return sema.arrayInitEmpty(block, inst_src, dest_ty);
2097820996 }
2097920997 if (inst_ty.isTuple()) {
2098020998 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
......@@ -22607,7 +22625,9 @@ fn beginComptimePtrMutation(
2260722625 }
2260822626 },
2260922627 .opt_payload_ptr => {
22610 const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
22628 const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else {
22629 return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena));
22630 };
2261122631 var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr, opt_ptr.container_ty);
2261222632 switch (parent.pointee) {
2261322633 .direct => |val_ptr| {
......@@ -22640,7 +22660,11 @@ fn beginComptimePtrMutation(
2264022660 .ty = payload_ty,
2264122661 },
2264222662
22643 else => unreachable,
22663 else => return ComptimePtrMutationKit{
22664 .decl_ref_mut = parent.decl_ref_mut,
22665 .pointee = .{ .direct = val_ptr },
22666 .ty = payload_ty,
22667 },
2264422668 }
2264522669 },
2264622670 .bad_decl_ty, .bad_ptr_ty => return parent,
......@@ -22922,8 +22946,13 @@ fn beginComptimePtrLoad(
2292222946 (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
2292322947 if (coerce_in_mem_ok) {
2292422948 const payload_val = switch (ptr_val.tag()) {
22925 .eu_payload_ptr => tv.val.castTag(.eu_payload).?.data,
22926 .opt_payload_ptr => tv.val.castTag(.opt_payload).?.data,
22949 .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else {
22950 return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name});
22951 },
22952 .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: {
22953 if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{});
22954 break :opt tv.val;
22955 },
2292722956 else => unreachable,
2292822957 };
2292922958 tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
......@@ -22933,6 +22962,9 @@ fn beginComptimePtrLoad(
2293322962 deref.pointee = null;
2293422963 break :blk deref;
2293522964 },
22965 .null_value => {
22966 return sema.fail(block, src, "attempt to use null value", .{});
22967 },
2293622968
2293722969 .zero,
2293822970 .one,
src/codegen/c.zig+3-2
......@@ -3618,8 +3618,9 @@ fn airIsErr(
36183618 const operand = try f.resolveInst(un_op);
36193619 const operand_ty = f.air.typeOf(un_op);
36203620 const local = try f.allocLocal(Type.initTag(.bool), .Const);
3621 const payload_ty = operand_ty.errorUnionPayload();
3622 const error_ty = operand_ty.errorUnionSet();
3621 const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;
3622 const payload_ty = err_union_ty.errorUnionPayload();
3623 const error_ty = err_union_ty.errorUnionSet();
36233624
36243625 try writer.writeAll(" = ");
36253626
src/codegen/llvm.zig+2-1
......@@ -5697,7 +5697,8 @@ pub const FuncGen = struct {
56975697
56985698 const un_op = self.air.instructions.items(.data)[inst].un_op;
56995699 const operand = try self.resolveInst(un_op);
5700 const err_union_ty = self.air.typeOf(un_op);
5700 const operand_ty = self.air.typeOf(un_op);
5701 const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
57015702 const payload_ty = err_union_ty.errorUnionPayload();
57025703 const err_set_ty = try self.dg.lowerType(Type.initTag(.anyerror));
57035704 const zero = err_set_ty.constNull();
test/behavior/error.zig+12
......@@ -724,3 +724,15 @@ test "simple else prong allowed even when all errors handled" {
724724 };
725725 try expect(value == 255);
726726}
727
728test {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
732 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
733
734 var err_union: anyerror!u8 = 15;
735
736 const payload_ptr = &(err_union catch unreachable);
737 try expect(payload_ptr.* == 15);
738}
test/behavior/eval.zig+21
......@@ -1272,3 +1272,24 @@ test "continue nested in a conditional in an inline for" {
12721272 }
12731273 try expect(x == 0);
12741274}
1275
1276test "optional pointer represented as a pointer value" {
1277 comptime {
1278 var val: u8 = 15;
1279 const opt_ptr: ?*u8 = &val;
1280
1281 const payload_ptr = &opt_ptr.?;
1282 try expect(payload_ptr.*.* == 15);
1283 }
1284}
1285
1286test "mutate through pointer-like optional at comptime" {
1287 comptime {
1288 var val: u8 = 15;
1289 var opt_ptr: ?*const u8 = &val;
1290
1291 const payload_ptr = &opt_ptr.?;
1292 payload_ptr.* = &@as(u8, 16);
1293 try expect(payload_ptr.*.* == 16);
1294 }
1295}
test/cases/compile_errors/array_init_invalid_elem_count.zig created+27
......@@ -0,0 +1,27 @@
1const V = @Vector(8, u8);
2const A = [8]u8;
3comptime {
4 var v: V = V{1};
5 _ = v;
6}
7comptime {
8 var v: V = V{};
9 _ = v;
10}
11comptime {
12 var a: A = A{1};
13 _ = a;
14}
15comptime {
16 var a: A = A{};
17 _ = a;
18}
19
20// error
21// backend=stage2
22// target=native
23//
24// :4:17: error: expected 8 vector elements; found 1
25// :8:17: error: expected 8 vector elements; found 0
26// :12:17: error: expected 8 array elements; found 1
27// :16:17: error: expected 8 array elements; found 0
test/cases/compile_errors/dereferencing_invalid_payload_ptr_at_comptime.zig created+33
......@@ -0,0 +1,33 @@
1const std = @import("std");
2
3comptime {
4 var val: u8 = 15;
5 var opt_ptr: ?*const u8 = &val;
6
7 const payload_ptr = &opt_ptr.?;
8 opt_ptr = null;
9 _ = payload_ptr.*.*;
10}
11comptime {
12 var opt: ?u8 = 15;
13
14 const payload_ptr = &opt.?;
15 opt = null;
16 _ = payload_ptr.*;
17}
18comptime {
19 var val: u8 = 15;
20 var err_union: anyerror!u8 = val;
21
22 const payload_ptr = &(err_union catch unreachable);
23 err_union = error.Foo;
24 _ = payload_ptr.*;
25}
26
27// error
28// backend=stage2
29// target=native
30//
31// :9:20: error: attempt to use null value
32// :16:20: error: attempt to use null value
33// :24:20: error: attempt to unwrap error: Foo