Commit e13a182990
Changed files (5)
test
stage2
src/codegen.zig
@@ -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 => {
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),
src/type.zig
@@ -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);
},
src/value.zig
@@ -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,
test/stage2/test.zig
@@ -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(