| ... | ... | @@ -1574,6 +1574,12 @@ fn failWithErrorSetCodeMissing( |
| 1574 | 1574 | }); |
| 1575 | 1575 | } |
| 1576 | 1576 | |
| 1577 | fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value) CompileError { |
| 1578 | return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{ |
| 1579 | int_ty.fmt(sema.mod), val.fmtValue(Type.@"comptime_int", sema.mod), |
| 1580 | }); |
| 1581 | } |
| 1582 | |
| 1577 | 1583 | /// We don't return a pointer to the new error note because the pointer |
| 1578 | 1584 | /// becomes invalid when you add another one. |
| 1579 | 1585 | fn errNote( |
| ... | ... | @@ -9711,10 +9717,11 @@ fn analyzeArithmetic( |
| 9711 | 9717 | } |
| 9712 | 9718 | if (maybe_rhs_val) |rhs_val| { |
| 9713 | 9719 | if (is_int) { |
| 9714 | | return sema.addConstant( |
| 9715 | | resolved_type, |
| 9716 | | try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target), |
| 9717 | | ); |
| 9720 | const sum = try lhs_val.intAdd(rhs_val, resolved_type, sema.arena, target); |
| 9721 | if (!sum.intFitsInType(resolved_type, target)) { |
| 9722 | return sema.failWithIntegerOverflow(block, src, resolved_type, sum); |
| 9723 | } |
| 9724 | return sema.addConstant(resolved_type, sum); |
| 9718 | 9725 | } else { |
| 9719 | 9726 | return sema.addConstant( |
| 9720 | 9727 | resolved_type, |
| ... | ... | @@ -9804,10 +9811,11 @@ fn analyzeArithmetic( |
| 9804 | 9811 | } |
| 9805 | 9812 | if (maybe_rhs_val) |rhs_val| { |
| 9806 | 9813 | if (is_int) { |
| 9807 | | return sema.addConstant( |
| 9808 | | resolved_type, |
| 9809 | | try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target), |
| 9810 | | ); |
| 9814 | const diff = try lhs_val.intSub(rhs_val, resolved_type, sema.arena, target); |
| 9815 | if (!diff.intFitsInType(resolved_type, target)) { |
| 9816 | return sema.failWithIntegerOverflow(block, src, resolved_type, diff); |
| 9817 | } |
| 9818 | return sema.addConstant(resolved_type, diff); |
| 9811 | 9819 | } else { |
| 9812 | 9820 | return sema.addConstant( |
| 9813 | 9821 | resolved_type, |
| ... | ... | @@ -10177,10 +10185,11 @@ fn analyzeArithmetic( |
| 10177 | 10185 | } |
| 10178 | 10186 | } |
| 10179 | 10187 | if (is_int) { |
| 10180 | | return sema.addConstant( |
| 10181 | | resolved_type, |
| 10182 | | try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target), |
| 10183 | | ); |
| 10188 | const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target); |
| 10189 | if (!product.intFitsInType(resolved_type, target)) { |
| 10190 | return sema.failWithIntegerOverflow(block, src, resolved_type, product); |
| 10191 | } |
| 10192 | return sema.addConstant(resolved_type, product); |
| 10184 | 10193 | } else { |
| 10185 | 10194 | return sema.addConstant( |
| 10186 | 10195 | resolved_type, |
| ... | ... | @@ -10468,6 +10477,45 @@ fn analyzeArithmetic( |
| 10468 | 10477 | }; |
| 10469 | 10478 | |
| 10470 | 10479 | try sema.requireRuntimeBlock(block, rs.src); |
| 10480 | if (block.wantSafety()) { |
| 10481 | if (scalar_tag == .Int) { |
| 10482 | const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) { |
| 10483 | .add => .add_with_overflow, |
| 10484 | .sub => .sub_with_overflow, |
| 10485 | .mul => .mul_with_overflow, |
| 10486 | else => null, |
| 10487 | }; |
| 10488 | if (maybe_op_ov) |op_ov_tag| { |
| 10489 | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type); |
| 10490 | const op_ov = try block.addInst(.{ |
| 10491 | .tag = op_ov_tag, |
| 10492 | .data = .{ .ty_pl = .{ |
| 10493 | .ty = try sema.addType(op_ov_tuple_ty), |
| 10494 | .payload = try sema.addExtra(Air.Bin{ |
| 10495 | .lhs = casted_lhs, |
| 10496 | .rhs = casted_rhs, |
| 10497 | }), |
| 10498 | } }, |
| 10499 | }); |
| 10500 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 10501 | const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector) |
| 10502 | try block.addInst(.{ |
| 10503 | .tag = .reduce, |
| 10504 | .data = .{ .reduce = .{ |
| 10505 | .operand = ov_bit, |
| 10506 | .operation = .Or, |
| 10507 | } }, |
| 10508 | }) |
| 10509 | else |
| 10510 | ov_bit; |
| 10511 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); |
| 10512 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 10513 | |
| 10514 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); |
| 10515 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); |
| 10516 | } |
| 10517 | } |
| 10518 | } |
| 10471 | 10519 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); |
| 10472 | 10520 | } |
| 10473 | 10521 | |
| ... | ... | @@ -16702,6 +16750,7 @@ pub const PanicId = enum { |
| 16702 | 16750 | invalid_error_code, |
| 16703 | 16751 | index_out_of_bounds, |
| 16704 | 16752 | cast_truncated_data, |
| 16753 | integer_overflow, |
| 16705 | 16754 | }; |
| 16706 | 16755 | |
| 16707 | 16756 | fn addSafetyCheck( |
| ... | ... | @@ -16825,6 +16874,7 @@ fn safetyPanic( |
| 16825 | 16874 | .invalid_error_code => "invalid error code", |
| 16826 | 16875 | .index_out_of_bounds => "attempt to index out of bounds", |
| 16827 | 16876 | .cast_truncated_data => "integer cast truncated bits", |
| 16877 | .integer_overflow => "integer overflow", |
| 16828 | 16878 | }; |
| 16829 | 16879 | |
| 16830 | 16880 | const msg_inst = msg_inst: { |