diff --git a/src/Sema.zig b/src/Sema.zig index 3015ac5d8e..8b8d828f54 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9027,6 +9027,10 @@ fn validateSwitchRange( ) CompileError!void { const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; + if (first_val.compare(.gt, last_val, operand_ty, sema.mod)) { + const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first); + return sema.fail(block, src, "range start value is greater than the end value", .{}); + } const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src); return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); } @@ -9374,9 +9378,34 @@ fn zirShl( if (rhs_val.isUndef()) { return sema.addConstUndef(sema.typeOf(lhs)); } + // If rhs is 0, return lhs without doing any calculations. if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { return lhs; } + if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) { + var bits_payload = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = scalar_ty.intInfo(target).bits, + }; + const bit_value = Value.initPayload(&bits_payload.base); + if (rhs_ty.zigTypeTag() == .Vector) { + var i: usize = 0; + while (i < rhs_ty.vectorLen()) : (i += 1) { + if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) { + return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod), + i, + scalar_ty.fmt(sema.mod), + }); + } + } + } else if (rhs_val.compareHetero(.gte, bit_value, target)) { + return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + rhs_val.fmtValue(scalar_ty, sema.mod), + scalar_ty.fmt(sema.mod), + }); + } + } } const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { @@ -9488,15 +9517,43 @@ fn zirShr( const rhs_ty = sema.typeOf(rhs); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); const target = sema.mod.getTarget(); + const scalar_ty = lhs_ty.scalarType(); const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: { - if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { - if (lhs_val.isUndef() or rhs_val.isUndef()) { - return sema.addConstUndef(lhs_ty); + if (rhs_val.isUndef()) { + return sema.addConstUndef(lhs_ty); + } + // If rhs is 0, return lhs without doing any calculations. + if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { + return lhs; + } + if (scalar_ty.zigTypeTag() != .ComptimeInt) { + var bits_payload = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = scalar_ty.intInfo(target).bits, + }; + const bit_value = Value.initPayload(&bits_payload.base); + if (rhs_ty.zigTypeTag() == .Vector) { + var i: usize = 0; + while (i < rhs_ty.vectorLen()) : (i += 1) { + if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) { + return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod), + i, + scalar_ty.fmt(sema.mod), + }); + } + } + } else if (rhs_val.compareHetero(.gte, bit_value, target)) { + return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + rhs_val.fmtValue(scalar_ty, sema.mod), + scalar_ty.fmt(sema.mod), + }); } - // If rhs is 0, return lhs without doing any calculations. - if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { - return sema.addConstant(lhs_ty, lhs_val); + } + if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { + if (lhs_val.isUndef()) { + return sema.addConstUndef(lhs_ty); } if (air_tag == .shr_exact) { // Detect if any ones would be shifted out. @@ -9508,12 +9565,6 @@ fn zirShr( const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target); return sema.addConstant(lhs_ty, val); } else { - // Even if lhs is not comptime known, we can still deduce certain things based - // on rhs. - // If rhs is 0, return lhs without doing any calculations. - if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) { - return lhs; - } break :rs lhs_src; } } else rhs_src; diff --git a/test/cases/compile_errors/stage1/test/shift_on_type_with_non-power-of-two_size.zig b/test/cases/compile_errors/shift_on_type_with_non-power-of-two_size.zig similarity index 61% rename from test/cases/compile_errors/stage1/test/shift_on_type_with_non-power-of-two_size.zig rename to test/cases/compile_errors/shift_on_type_with_non-power-of-two_size.zig index 222cb22563..9f606b0426 100644 --- a/test/cases/compile_errors/stage1/test/shift_on_type_with_non-power-of-two_size.zig +++ b/test/cases/compile_errors/shift_on_type_with_non-power-of-two_size.zig @@ -24,11 +24,10 @@ export fn entry() void { } // error -// backend=stage1 +// backend=stage2 // target=native -// is_test=1 // -// tmp.zig:5:19: error: RHS of shift is too large for LHS type -// tmp.zig:9:19: error: RHS of shift is too large for LHS type -// tmp.zig:13:17: error: RHS of shift is too large for LHS type -// tmp.zig:17:17: error: RHS of shift is too large for LHS type +// :5:22: error: shift amount '24' is too large for operand type 'u24' +// :9:22: error: shift amount '24' is too large for operand type 'u24' +// :13:30: error: shift amount '24' is too large for operand type 'u24' +// :17:30: error: shift amount '24' is too large for operand type 'u24' diff --git a/test/cases/compile_errors/stage1/test/switch_ranges_endpoints_are_validated.zig b/test/cases/compile_errors/stage1/test/switch_ranges_endpoints_are_validated.zig deleted file mode 100644 index a44d59feed..0000000000 --- a/test/cases/compile_errors/stage1/test/switch_ranges_endpoints_are_validated.zig +++ /dev/null @@ -1,16 +0,0 @@ -pub export fn entry() void { - var x: i32 = 0; - switch (x) { - 6...1 => {}, - -1...-5 => {}, - else => unreachable, - } -} - -// error -// backend=stage1 -// target=native -// is_test=1 -// -// tmp.zig:4:9: error: range start value is greater than the end value -// tmp.zig:5:9: error: range start value is greater than the end value diff --git a/test/cases/compile_errors/switch_ranges_endpoints_are_validated.zig b/test/cases/compile_errors/switch_ranges_endpoints_are_validated.zig new file mode 100644 index 0000000000..72c17929c0 --- /dev/null +++ b/test/cases/compile_errors/switch_ranges_endpoints_are_validated.zig @@ -0,0 +1,21 @@ +pub export fn entry1() void { + var x: i32 = 0; + switch (x) { + 6...1 => {}, + else => unreachable, + } +} +pub export fn entr2() void { + var x: i32 = 0; + switch (x) { + -1...-5 => {}, + else => unreachable, + } +} + +// error +// backend=stage2 +// target=native +// +// :4:9: error: range start value is greater than the end value +// :11:9: error: range start value is greater than the end value