mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Sema: fix shl_sat with comptime rhs
This commit is contained in:
parent
1adb15098c
commit
c64279b15b
53
src/Sema.zig
53
src/Sema.zig
@ -6398,7 +6398,6 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
@ -6406,16 +6405,29 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
|
||||
const operand = sema.resolveInst(extra.rhs);
|
||||
|
||||
return sema.intCast(block, dest_ty, dest_ty_src, operand, operand_src, true);
|
||||
}
|
||||
|
||||
fn intCast(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
dest_ty: Type,
|
||||
dest_ty_src: LazySrcLoc,
|
||||
operand: Air.Inst.Ref,
|
||||
operand_src: LazySrcLoc,
|
||||
runtime_safety: bool,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty);
|
||||
_ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
|
||||
|
||||
if (try sema.isComptimeKnown(block, operand_src, operand)) {
|
||||
return sema.coerce(block, dest_ty, operand, operand_src);
|
||||
} else if (dest_is_comptime_int) {
|
||||
return sema.fail(block, src, "unable to cast runtime value to 'comptime_int'", .{});
|
||||
return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
|
||||
}
|
||||
|
||||
// TODO insert safety check to make sure the value fits in the dest type
|
||||
_ = runtime_safety;
|
||||
|
||||
if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
|
||||
return sema.addConstant(dest_ty, opv);
|
||||
@ -7986,6 +7998,7 @@ fn zirShl(
|
||||
const rhs = sema.resolveInst(extra.rhs);
|
||||
|
||||
// TODO coerce rhs if air_tag is not shl_sat
|
||||
const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, sema.typeOf(rhs));
|
||||
|
||||
const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
|
||||
const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
|
||||
@ -7999,13 +8012,14 @@ fn zirShl(
|
||||
}
|
||||
}
|
||||
|
||||
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
|
||||
const lhs_ty = sema.typeOf(lhs);
|
||||
const rhs_ty = sema.typeOf(rhs);
|
||||
const target = sema.mod.getTarget();
|
||||
|
||||
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
|
||||
if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
|
||||
const rhs_val = maybe_rhs_val orelse break :rs rhs_src;
|
||||
|
||||
const target = sema.mod.getTarget();
|
||||
const val = switch (air_tag) {
|
||||
.shl_exact => val: {
|
||||
const shifted = try lhs_val.shl(rhs_val, sema.arena);
|
||||
@ -8038,8 +8052,24 @@ fn zirShl(
|
||||
|
||||
// TODO: insert runtime safety check for shl_exact
|
||||
|
||||
const new_rhs = if (air_tag == .shl_sat) rhs: {
|
||||
// Limit the RHS type for saturating shl to be an integer as small as the LHS.
|
||||
if (rhs_is_comptime_int or
|
||||
rhs_ty.intInfo(target).bits > lhs_ty.intInfo(target).bits)
|
||||
{
|
||||
const max_int = try sema.addConstant(
|
||||
lhs_ty,
|
||||
try lhs_ty.maxInt(sema.arena, target),
|
||||
);
|
||||
const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src);
|
||||
break :rhs try sema.intCast(block, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
|
||||
} else {
|
||||
break :rhs rhs;
|
||||
}
|
||||
} else rhs;
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
return block.addBinOp(air_tag, lhs, rhs);
|
||||
return block.addBinOp(air_tag, lhs, new_rhs);
|
||||
}
|
||||
|
||||
fn zirShr(
|
||||
@ -14537,6 +14567,19 @@ fn zirMinMax(
|
||||
const rhs = sema.resolveInst(extra.rhs);
|
||||
try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs));
|
||||
try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs));
|
||||
return sema.analyzeMinMax(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
|
||||
}
|
||||
|
||||
fn analyzeMinMax(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
lhs: Air.Inst.Ref,
|
||||
rhs: Air.Inst.Ref,
|
||||
air_tag: Air.Inst.Tag,
|
||||
lhs_src: LazySrcLoc,
|
||||
rhs_src: LazySrcLoc,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
|
||||
|
||||
// TODO @maximum(max_int, undefined) should return max_int
|
||||
|
||||
@ -609,7 +609,11 @@ test "negation f64" {
|
||||
}
|
||||
|
||||
test "negation f80" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// This test case exercises @intToFloat f80 in the compiler implementation.
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .freebsd) {
|
||||
// TODO file issue to track this failure
|
||||
@ -673,7 +677,10 @@ fn fnWithFloatMode() f32 {
|
||||
}
|
||||
|
||||
test "float literal at compile time not lossy" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// https://github.com/ziglang/zig/issues/11169
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try expect(16777216.0 + 1.0 == 16777217.0);
|
||||
try expect(9007199254740992.0 + 1.0 == 9007199254740993.0);
|
||||
|
||||
@ -307,13 +307,20 @@ fn acceptsString(foo: []u8) void {
|
||||
}
|
||||
|
||||
test "function pointers" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
// stage1 has wrong semantics for function pointers
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
const fns = [_]@TypeOf(fn1){
|
||||
fn1,
|
||||
fn2,
|
||||
fn3,
|
||||
fn4,
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const fns = [_]*const @TypeOf(fn1){
|
||||
&fn1,
|
||||
&fn2,
|
||||
&fn3,
|
||||
&fn4,
|
||||
};
|
||||
for (fns) |f, i| {
|
||||
try expect(f() == @intCast(u32, i) + 5);
|
||||
@ -380,7 +387,9 @@ test "ability to give comptime types and non comptime types to same parameter" {
|
||||
}
|
||||
|
||||
test "function with inferred error set but returning no error" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn foo() !void {}
|
||||
|
||||
@ -163,8 +163,6 @@ test "saturating shift-left" {
|
||||
}
|
||||
|
||||
test "saturating shl uses the LHS type" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
const lhs_const: u8 = 1;
|
||||
var lhs_var: u8 = 1;
|
||||
|
||||
|
||||
@ -45,16 +45,16 @@ test "cast negative integer to pointer" {
|
||||
}
|
||||
|
||||
test "casting to union with a macro" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO Sema.zirUnionInitPtr
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
|
||||
const l: c_long = 42;
|
||||
const d: f64 = 2.0;
|
||||
|
||||
var casted = h.UNION_CAST(l);
|
||||
try expectEqual(l, casted.l);
|
||||
try expect(l == casted.l);
|
||||
|
||||
casted = h.UNION_CAST(d);
|
||||
try expectEqual(d, casted.d);
|
||||
try expect(d == casted.d);
|
||||
}
|
||||
|
||||
test "nested comma operator" {
|
||||
|
||||
@ -230,7 +230,10 @@ test "Type.Vector" {
|
||||
}
|
||||
|
||||
test "Type.AnyFrame" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// https://github.com/ziglang/zig/issues/6025
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testTypes(&[_]type{
|
||||
anyframe,
|
||||
@ -514,39 +517,3 @@ test "Type.Union from regular enum" {
|
||||
_ = T;
|
||||
_ = @typeInfo(T).Union;
|
||||
}
|
||||
|
||||
test "Type.Fn" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// wasm doesn't support align attributes on functions
|
||||
if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
|
||||
|
||||
const foo = struct {
|
||||
fn func(a: usize, b: bool) align(4) callconv(.C) usize {
|
||||
_ = a;
|
||||
_ = b;
|
||||
return 0;
|
||||
}
|
||||
}.func;
|
||||
const Foo = @Type(@typeInfo(@TypeOf(foo)));
|
||||
const foo_2: Foo = foo;
|
||||
_ = foo_2;
|
||||
}
|
||||
|
||||
test "Type.BoundFn" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// wasm doesn't support align attributes on functions
|
||||
if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
|
||||
|
||||
const TestStruct = packed struct {
|
||||
pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {
|
||||
_ = self;
|
||||
}
|
||||
};
|
||||
const test_instance: TestStruct = undefined;
|
||||
try testing.expect(std.meta.eql(
|
||||
@typeName(@TypeOf(test_instance.foo)),
|
||||
@typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
|
||||
));
|
||||
}
|
||||
|
||||
@ -379,12 +379,6 @@ fn testFunction() !void {
|
||||
try expect(fn_info.Fn.return_type.? == usize);
|
||||
const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
|
||||
try expect(fn_aligned_info.Fn.alignment == 4);
|
||||
|
||||
if (builtin.zig_backend != .stage1) return; // no bound fn in stage2
|
||||
const test_instance: TestPackedStruct = undefined;
|
||||
const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
|
||||
try expect(bound_fn_info == .BoundFn);
|
||||
try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestPackedStruct);
|
||||
}
|
||||
|
||||
extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
|
||||
@ -413,7 +407,10 @@ fn testVector() !void {
|
||||
}
|
||||
|
||||
test "type info: anyframe and anyframe->T" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// https://github.com/ziglang/zig/issues/6025
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testAnyFrame();
|
||||
comptime try testAnyFrame();
|
||||
@ -469,7 +466,10 @@ fn add(a: i32, b: i32) i32 {
|
||||
}
|
||||
|
||||
test "type info for async frames" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// https://github.com/ziglang/zig/issues/6025
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
switch (@typeInfo(@Frame(add))) {
|
||||
.Frame => |frame| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user