diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-14 23:15:01 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-03-14 23:15:01 -0700 |
| commit | c64279b15b527749420e0e79fcc6dbfbfeb02812 (patch) | |
| tree | 8f7fe813a6b2b7048468731f5f93619b3704e882 | |
| parent | 1adb15098c711973d1c75061f122b907aaf09a7c (diff) | |
| download | zig-c64279b15b527749420e0e79fcc6dbfbfeb02812.tar.gz zig-c64279b15b527749420e0e79fcc6dbfbfeb02812.zip | |
Sema: fix shl_sat with comptime rhs
| -rw-r--r-- | src/Sema.zig | 55 | ||||
| -rw-r--r-- | test/behavior/floatop.zig | 11 | ||||
| -rw-r--r-- | test/behavior/fn.zig | 23 | ||||
| -rw-r--r-- | test/behavior/saturating_arithmetic.zig | 2 | ||||
| -rw-r--r-- | test/behavior/translate_c_macros.zig | 6 | ||||
| -rw-r--r-- | test/behavior/type.zig | 41 | ||||
| -rw-r--r-- | test/behavior/type_info.zig | 16 |
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| { |
