mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
Merge pull request #12198 from Vexu/stage2
Sema: fix loading and storing of optional pointers represented as pointers
This commit is contained in:
commit
f591936480
62
src/Sema.zig
62
src/Sema.zig
@ -1663,11 +1663,15 @@ fn resolveMaybeUndefValIntable(
|
||||
inst: Air.Inst.Ref,
|
||||
) CompileError!?Value {
|
||||
const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
|
||||
switch (val.tag()) {
|
||||
.variable, .decl_ref, .decl_ref_mut => return null,
|
||||
var check = val;
|
||||
while (true) switch (check.tag()) {
|
||||
.variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
|
||||
.field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
|
||||
.elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
|
||||
.eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
|
||||
.generic_poison => return error.GenericPoison,
|
||||
else => return val,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns all Value tags including `variable` and `undef`.
|
||||
@ -3871,9 +3875,15 @@ fn zirValidateArrayInit(
|
||||
const array_len = array_ty.arrayLen();
|
||||
|
||||
if (instrs.len != array_len) {
|
||||
return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
|
||||
array_len, instrs.len,
|
||||
});
|
||||
if (array_ty.zigTypeTag() == .Array) {
|
||||
return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
|
||||
array_len, instrs.len,
|
||||
});
|
||||
} else {
|
||||
return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
|
||||
array_len, instrs.len,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ((is_comptime or block.is_comptime) and
|
||||
@ -7893,7 +7903,7 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
if (!ptr_ty.isPtrAtRuntime()) {
|
||||
return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)});
|
||||
}
|
||||
if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
|
||||
if (try sema.resolveMaybeUndefValIntable(block, ptr_src, ptr)) |ptr_val| {
|
||||
return sema.addConstant(Type.usize, ptr_val);
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, ptr_src, ptr_src);
|
||||
@ -14261,7 +14271,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
|
||||
|
||||
switch (obj_ty.zigTypeTag()) {
|
||||
.Struct => return sema.structInitEmpty(block, obj_ty, src, src),
|
||||
.Array => return arrayInitEmpty(sema, obj_ty),
|
||||
.Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty),
|
||||
.Void => return sema.addConstant(obj_ty, Value.void),
|
||||
else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
|
||||
}
|
||||
@ -14286,7 +14296,15 @@ fn structInitEmpty(
|
||||
return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);
|
||||
}
|
||||
|
||||
fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
|
||||
fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
|
||||
const arr_len = obj_ty.arrayLen();
|
||||
if (arr_len != 0) {
|
||||
if (obj_ty.zigTypeTag() == .Array) {
|
||||
return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len});
|
||||
} else {
|
||||
return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len});
|
||||
}
|
||||
}
|
||||
if (obj_ty.sentinel()) |sentinel| {
|
||||
const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel);
|
||||
return sema.addConstant(obj_ty, val);
|
||||
@ -19448,7 +19466,7 @@ fn fieldCallBind(
|
||||
|
||||
const raw_ptr_src = src; // TODO better source location
|
||||
const raw_ptr_ty = sema.typeOf(raw_ptr);
|
||||
const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and raw_ptr_ty.ptrSize() == .One)
|
||||
const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C))
|
||||
raw_ptr_ty.childType()
|
||||
else
|
||||
return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)});
|
||||
@ -20974,7 +20992,7 @@ fn coerceExtra(
|
||||
.Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
|
||||
.Struct => {
|
||||
if (inst == .empty_struct) {
|
||||
return arrayInitEmpty(sema, dest_ty);
|
||||
return sema.arrayInitEmpty(block, inst_src, dest_ty);
|
||||
}
|
||||
if (inst_ty.isTuple()) {
|
||||
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
@ -22607,7 +22625,9 @@ fn beginComptimePtrMutation(
|
||||
}
|
||||
},
|
||||
.opt_payload_ptr => {
|
||||
const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
|
||||
const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else {
|
||||
return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena));
|
||||
};
|
||||
var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr.container_ptr, opt_ptr.container_ty);
|
||||
switch (parent.pointee) {
|
||||
.direct => |val_ptr| {
|
||||
@ -22640,7 +22660,11 @@ fn beginComptimePtrMutation(
|
||||
.ty = payload_ty,
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
else => return ComptimePtrMutationKit{
|
||||
.decl_ref_mut = parent.decl_ref_mut,
|
||||
.pointee = .{ .direct = val_ptr },
|
||||
.ty = payload_ty,
|
||||
},
|
||||
}
|
||||
},
|
||||
.bad_decl_ty, .bad_ptr_ty => return parent,
|
||||
@ -22922,8 +22946,13 @@ fn beginComptimePtrLoad(
|
||||
(try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
|
||||
if (coerce_in_mem_ok) {
|
||||
const payload_val = switch (ptr_val.tag()) {
|
||||
.eu_payload_ptr => tv.val.castTag(.eu_payload).?.data,
|
||||
.opt_payload_ptr => tv.val.castTag(.opt_payload).?.data,
|
||||
.eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else {
|
||||
return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name});
|
||||
},
|
||||
.opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: {
|
||||
if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{});
|
||||
break :opt tv.val;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
|
||||
@ -22933,6 +22962,9 @@ fn beginComptimePtrLoad(
|
||||
deref.pointee = null;
|
||||
break :blk deref;
|
||||
},
|
||||
.null_value => {
|
||||
return sema.fail(block, src, "attempt to use null value", .{});
|
||||
},
|
||||
|
||||
.zero,
|
||||
.one,
|
||||
|
||||
@ -3618,8 +3618,9 @@ fn airIsErr(
|
||||
const operand = try f.resolveInst(un_op);
|
||||
const operand_ty = f.air.typeOf(un_op);
|
||||
const local = try f.allocLocal(Type.initTag(.bool), .Const);
|
||||
const payload_ty = operand_ty.errorUnionPayload();
|
||||
const error_ty = operand_ty.errorUnionSet();
|
||||
const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;
|
||||
const payload_ty = err_union_ty.errorUnionPayload();
|
||||
const error_ty = err_union_ty.errorUnionSet();
|
||||
|
||||
try writer.writeAll(" = ");
|
||||
|
||||
|
||||
@ -5697,7 +5697,8 @@ pub const FuncGen = struct {
|
||||
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
const operand = try self.resolveInst(un_op);
|
||||
const err_union_ty = self.air.typeOf(un_op);
|
||||
const operand_ty = self.air.typeOf(un_op);
|
||||
const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
|
||||
const payload_ty = err_union_ty.errorUnionPayload();
|
||||
const err_set_ty = try self.dg.lowerType(Type.initTag(.anyerror));
|
||||
const zero = err_set_ty.constNull();
|
||||
|
||||
@ -724,3 +724,15 @@ test "simple else prong allowed even when all errors handled" {
|
||||
};
|
||||
try expect(value == 255);
|
||||
}
|
||||
|
||||
test {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
|
||||
var err_union: anyerror!u8 = 15;
|
||||
|
||||
const payload_ptr = &(err_union catch unreachable);
|
||||
try expect(payload_ptr.* == 15);
|
||||
}
|
||||
|
||||
@ -1272,3 +1272,24 @@ test "continue nested in a conditional in an inline for" {
|
||||
}
|
||||
try expect(x == 0);
|
||||
}
|
||||
|
||||
test "optional pointer represented as a pointer value" {
|
||||
comptime {
|
||||
var val: u8 = 15;
|
||||
const opt_ptr: ?*u8 = &val;
|
||||
|
||||
const payload_ptr = &opt_ptr.?;
|
||||
try expect(payload_ptr.*.* == 15);
|
||||
}
|
||||
}
|
||||
|
||||
test "mutate through pointer-like optional at comptime" {
|
||||
comptime {
|
||||
var val: u8 = 15;
|
||||
var opt_ptr: ?*const u8 = &val;
|
||||
|
||||
const payload_ptr = &opt_ptr.?;
|
||||
payload_ptr.* = &@as(u8, 16);
|
||||
try expect(payload_ptr.*.* == 16);
|
||||
}
|
||||
}
|
||||
|
||||
27
test/cases/compile_errors/array_init_invalid_elem_count.zig
Normal file
27
test/cases/compile_errors/array_init_invalid_elem_count.zig
Normal file
@ -0,0 +1,27 @@
|
||||
const V = @Vector(8, u8);
|
||||
const A = [8]u8;
|
||||
comptime {
|
||||
var v: V = V{1};
|
||||
_ = v;
|
||||
}
|
||||
comptime {
|
||||
var v: V = V{};
|
||||
_ = v;
|
||||
}
|
||||
comptime {
|
||||
var a: A = A{1};
|
||||
_ = a;
|
||||
}
|
||||
comptime {
|
||||
var a: A = A{};
|
||||
_ = a;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:17: error: expected 8 vector elements; found 1
|
||||
// :8:17: error: expected 8 vector elements; found 0
|
||||
// :12:17: error: expected 8 array elements; found 1
|
||||
// :16:17: error: expected 8 array elements; found 0
|
||||
@ -0,0 +1,33 @@
|
||||
const std = @import("std");
|
||||
|
||||
comptime {
|
||||
var val: u8 = 15;
|
||||
var opt_ptr: ?*const u8 = &val;
|
||||
|
||||
const payload_ptr = &opt_ptr.?;
|
||||
opt_ptr = null;
|
||||
_ = payload_ptr.*.*;
|
||||
}
|
||||
comptime {
|
||||
var opt: ?u8 = 15;
|
||||
|
||||
const payload_ptr = &opt.?;
|
||||
opt = null;
|
||||
_ = payload_ptr.*;
|
||||
}
|
||||
comptime {
|
||||
var val: u8 = 15;
|
||||
var err_union: anyerror!u8 = val;
|
||||
|
||||
const payload_ptr = &(err_union catch unreachable);
|
||||
err_union = error.Foo;
|
||||
_ = payload_ptr.*;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :9:20: error: attempt to use null value
|
||||
// :16:20: error: attempt to use null value
|
||||
// :24:20: error: attempt to unwrap error: Foo
|
||||
Loading…
x
Reference in New Issue
Block a user