stage2 Sema: implement @intToPtr (#9144)
Co-authored-by: Veikka Tuominen <git@vexu.eu>
This commit is contained in:
72
src/Sema.zig
72
src/Sema.zig
@@ -5758,7 +5758,65 @@ fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
|
||||
fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{});
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
|
||||
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
|
||||
const operand_res = try sema.resolveInst(extra.rhs);
|
||||
const operand_coerced = try sema.coerce(block, Type.initTag(.usize), operand_res, operand_src);
|
||||
|
||||
const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||
const type_res = try sema.resolveType(block, src, extra.lhs);
|
||||
if (type_res.zigTypeTag() != .Pointer)
|
||||
return sema.mod.fail(&block.base, type_src, "expected pointer, found '{}'", .{type_res});
|
||||
const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
|
||||
|
||||
const uncasted_operand = try sema.resolveInst(extra.rhs);
|
||||
if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
|
||||
const addr = val.toUnsignedInt();
|
||||
if (!type_res.isAllowzeroPtr() and addr == 0)
|
||||
return sema.mod.fail(&block.base, operand_src, "pointer type '{}' does not allow address zero", .{type_res});
|
||||
if (addr != 0 and addr % ptr_align != 0)
|
||||
return sema.mod.fail(&block.base, operand_src, "pointer type '{}' requires aligned address", .{type_res});
|
||||
|
||||
const val_payload = try sema.arena.create(Value.Payload.U64);
|
||||
val_payload.* = .{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = addr,
|
||||
};
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = type_res,
|
||||
.val = Value.initPayload(&val_payload.base),
|
||||
});
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
if (block.wantSafety()) {
|
||||
const zero = try sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = Type.initTag(.u64),
|
||||
.val = Value.initTag(.zero),
|
||||
});
|
||||
if (!type_res.isAllowzeroPtr()) {
|
||||
const is_non_zero = try block.addBinOp(src, Type.initTag(.bool), .cmp_neq, operand_coerced, zero);
|
||||
try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
|
||||
}
|
||||
|
||||
if (ptr_align > 1) {
|
||||
const val_payload = try sema.arena.create(Value.Payload.U64);
|
||||
val_payload.* = .{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = ptr_align - 1,
|
||||
};
|
||||
const align_minus_1 = try sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = Type.initTag(.u64),
|
||||
.val = Value.initPayload(&val_payload.base),
|
||||
});
|
||||
const remainder = try block.addBinOp(src, Type.initTag(.u64), .bit_and, operand_coerced, align_minus_1);
|
||||
const is_aligned = try block.addBinOp(src, Type.initTag(.bool), .cmp_eq, remainder, zero);
|
||||
try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
|
||||
}
|
||||
}
|
||||
return block.addUnOp(src, type_res, .bitcast, operand_coerced);
|
||||
}
|
||||
|
||||
fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
|
||||
@@ -6183,6 +6241,8 @@ pub const PanicId = enum {
|
||||
unreach,
|
||||
unwrap_null,
|
||||
unwrap_errunion,
|
||||
cast_to_null,
|
||||
incorrect_alignment,
|
||||
invalid_error_code,
|
||||
};
|
||||
|
||||
@@ -6805,10 +6865,13 @@ fn storePtr(
|
||||
if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
|
||||
return;
|
||||
|
||||
if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| {
|
||||
if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {
|
||||
const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse
|
||||
return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
|
||||
|
||||
if (ptr_val.tag() == .int_u64)
|
||||
break :blk; // propogate it down to runtime
|
||||
|
||||
const comptime_alloc = ptr_val.castTag(.comptime_alloc).?;
|
||||
if (comptime_alloc.data.runtime_index < block.runtime_index) {
|
||||
if (block.runtime_cond) |cond_src| {
|
||||
@@ -6947,7 +7010,10 @@ fn analyzeLoad(
|
||||
.Pointer => ptr.ty.elemType(),
|
||||
else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
|
||||
};
|
||||
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
|
||||
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| blk: {
|
||||
if (ptr_val.tag() == .int_u64)
|
||||
break :blk; // do it at runtime
|
||||
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = elem_ty,
|
||||
.val = try ptr_val.pointerDeref(sema.arena),
|
||||
|
||||
@@ -4169,6 +4169,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
|
||||
}
|
||||
}
|
||||
if (typed_value.val.tag() == .int_u64) {
|
||||
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
|
||||
}
|
||||
return self.fail(src, "TODO codegen more kinds of const pointers", .{});
|
||||
},
|
||||
.Int => {
|
||||
|
||||
@@ -1538,7 +1538,7 @@ pub const Type = extern union {
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) return 1;
|
||||
if (!self.elemType().hasCodeGenBits()) return 1;
|
||||
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
|
||||
},
|
||||
|
||||
@@ -1550,7 +1550,7 @@ pub const Type = extern union {
|
||||
.c_mut_pointer,
|
||||
.pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) return 0;
|
||||
if (!self.elemType().hasCodeGenBits()) return 0;
|
||||
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
|
||||
},
|
||||
|
||||
|
||||
@@ -979,6 +979,26 @@ pub const Value = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the value is numeric
|
||||
pub fn isZero(self: Value) bool {
|
||||
return switch (self.tag()) {
|
||||
.zero => true,
|
||||
.one => false,
|
||||
|
||||
.int_u64 => self.castTag(.int_u64).?.data == 0,
|
||||
.int_i64 => self.castTag(.int_i64).?.data == 0,
|
||||
|
||||
.float_16 => self.castTag(.float_16).?.data == 0,
|
||||
.float_32 => self.castTag(.float_32).?.data == 0,
|
||||
.float_64 => self.castTag(.float_64).?.data == 0,
|
||||
.float_128 => self.castTag(.float_128).?.data == 0,
|
||||
|
||||
.int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
|
||||
.int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn orderAgainstZero(lhs: Value) std.math.Order {
|
||||
return switch (lhs.tag()) {
|
||||
.zero,
|
||||
|
||||
@@ -1000,6 +1000,24 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\}
|
||||
, &[_][]const u8{":2:3: error: this is an error"});
|
||||
|
||||
{
|
||||
var case = ctx.exe("intToPtr", linux_x64);
|
||||
case.addError(
|
||||
\\pub fn main() void {
|
||||
\\ _ = @intToPtr(*u8, 0);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
":2:24: error: pointer type '*u8' does not allow address zero",
|
||||
});
|
||||
case.addError(
|
||||
\\pub fn main() void {
|
||||
\\ _ = @intToPtr(*u32, 2);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
":2:25: error: pointer type '*u32' requires aligned address",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.obj("variable shadowing", linux_x64);
|
||||
case.addError(
|
||||
|
||||
Reference in New Issue
Block a user