aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-14 23:15:01 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-14 23:15:01 -0700
commitc64279b15b527749420e0e79fcc6dbfbfeb02812 (patch)
tree8f7fe813a6b2b7048468731f5f93619b3704e882
parent1adb15098c711973d1c75061f122b907aaf09a7c (diff)
downloadzig-c64279b15b527749420e0e79fcc6dbfbfeb02812.tar.gz
zig-c64279b15b527749420e0e79fcc6dbfbfeb02812.zip
Sema: fix shl_sat with comptime rhs
-rw-r--r--src/Sema.zig55
-rw-r--r--test/behavior/floatop.zig11
-rw-r--r--test/behavior/fn.zig23
-rw-r--r--test/behavior/saturating_arithmetic.zig2
-rw-r--r--test/behavior/translate_c_macros.zig6
-rw-r--r--test/behavior/type.zig41
-rw-r--r--test/behavior/type_info.zig16
7 files changed, 89 insertions, 65 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 57522bcfd5..118149645d 100644
--- a/src/Sema.zig
+++ b/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 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
diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig
index 424677ea1c..f8445b6e26 100644
--- a/test/behavior/floatop.zig
+++ b/test/behavior/floatop.zig
@@ -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);
diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig
index 93bc712227..c6b5a4efc9 100644
--- a/test/behavior/fn.zig
+++ b/test/behavior/fn.zig
@@ -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;
+ }
+
+ 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 = [_]@TypeOf(fn1){
- fn1,
- fn2,
- fn3,
- fn4,
+ 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 {}
diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig
index c596c50a15..54bdeb83e2 100644
--- a/test/behavior/saturating_arithmetic.zig
+++ b/test/behavior/saturating_arithmetic.zig
@@ -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;
diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig
index 3dd7f5aad7..8128f8112f 100644
--- a/test/behavior/translate_c_macros.zig
+++ b/test/behavior/translate_c_macros.zig
@@ -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" {
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
index 0335bd3589..9d236071f2 100644
--- a/test/behavior/type.zig
+++ b/test/behavior/type.zig
@@ -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)))),
- ));
-}
diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig
index b2ea6ecbe0..4231803ecd 100644
--- a/test/behavior/type_info.zig
+++ b/test/behavior/type_info.zig
@@ -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| {