| ... | @@ -16857,7 +16857,6 @@ pub const PanicId = enum { | ... | @@ -16857,7 +16857,6 @@ pub const PanicId = enum { |
| 16857 | cast_to_null, | 16857 | cast_to_null, |
| 16858 | incorrect_alignment, | 16858 | incorrect_alignment, |
| 16859 | invalid_error_code, | 16859 | invalid_error_code, |
| 16860 | index_out_of_bounds, | | |
| 16861 | cast_truncated_data, | 16860 | cast_truncated_data, |
| 16862 | integer_overflow, | 16861 | integer_overflow, |
| 16863 | shl_overflow, | 16862 | shl_overflow, |
| ... | @@ -16886,6 +16885,17 @@ fn addSafetyCheck( | ... | @@ -16886,6 +16885,17 @@ fn addSafetyCheck( |
| 16886 | | 16885 | |
| 16887 | _ = try sema.safetyPanic(&fail_block, .unneeded, panic_id); | 16886 | _ = try sema.safetyPanic(&fail_block, .unneeded, panic_id); |
| 16888 | | 16887 | |
| | 16888 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); |
| | 16889 | } |
| | 16890 | |
| | 16891 | fn addSafetyCheckExtra( |
| | 16892 | sema: *Sema, |
| | 16893 | parent_block: *Block, |
| | 16894 | ok: Air.Inst.Ref, |
| | 16895 | fail_block: *Block, |
| | 16896 | ) !void { |
| | 16897 | const gpa = sema.gpa; |
| | 16898 | |
| 16889 | try parent_block.instructions.ensureUnusedCapacity(gpa, 1); | 16899 | try parent_block.instructions.ensureUnusedCapacity(gpa, 1); |
| 16890 | | 16900 | |
| 16891 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + | 16901 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + |
| ... | @@ -16994,7 +17004,6 @@ fn panicUnwrapError( | ... | @@ -16994,7 +17004,6 @@ fn panicUnwrapError( |
| 16994 | | 17004 | |
| 16995 | { | 17005 | { |
| 16996 | const this_feature_is_implemented_in_the_backend = | 17006 | const this_feature_is_implemented_in_the_backend = |
| 16997 | sema.mod.comp.bin_file.options.object_format == .c or | | |
| 16998 | sema.mod.comp.bin_file.options.use_llvm; | 17007 | sema.mod.comp.bin_file.options.use_llvm; |
| 16999 | | 17008 | |
| 17000 | if (!this_feature_is_implemented_in_the_backend) { | 17009 | if (!this_feature_is_implemented_in_the_backend) { |
| ... | @@ -17009,52 +17018,48 @@ fn panicUnwrapError( | ... | @@ -17009,52 +17018,48 @@ fn panicUnwrapError( |
| 17009 | _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args); | 17018 | _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args); |
| 17010 | } | 17019 | } |
| 17011 | } | 17020 | } |
| | 17021 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); |
| | 17022 | } |
| 17012 | | 17023 | |
| 17013 | try parent_block.instructions.ensureUnusedCapacity(gpa, 1); | 17024 | fn panicIndexOutOfBounds( |
| 17014 | | 17025 | sema: *Sema, |
| 17015 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + | 17026 | parent_block: *Block, |
| 17016 | 1 + // The main block only needs space for the cond_br. | 17027 | src: LazySrcLoc, |
| 17017 | @typeInfo(Air.CondBr).Struct.fields.len + | 17028 | index: Air.Inst.Ref, |
| 17018 | 1 + // The ok branch of the cond_br only needs space for the br. | 17029 | len: Air.Inst.Ref, |
| 17019 | fail_block.instructions.items.len); | 17030 | cmp_op: Air.Inst.Tag, |
| | 17031 | ) !void { |
| | 17032 | const ok = try parent_block.addBinOp(cmp_op, index, len); |
| | 17033 | const gpa = sema.gpa; |
| 17020 | | 17034 | |
| 17021 | try sema.air_instructions.ensureUnusedCapacity(gpa, 3); | 17035 | var fail_block: Block = .{ |
| 17022 | const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); | 17036 | .parent = parent_block, |
| 17023 | const cond_br_inst = block_inst + 1; | 17037 | .sema = sema, |
| 17024 | const br_inst = cond_br_inst + 1; | 17038 | .src_decl = parent_block.src_decl, |
| 17025 | sema.air_instructions.appendAssumeCapacity(.{ | 17039 | .namespace = parent_block.namespace, |
| 17026 | .tag = .block, | 17040 | .wip_capture_scope = parent_block.wip_capture_scope, |
| 17027 | .data = .{ .ty_pl = .{ | 17041 | .instructions = .{}, |
| 17028 | .ty = .void_type, | 17042 | .inlining = parent_block.inlining, |
| 17029 | .payload = sema.addExtraAssumeCapacity(Air.Block{ | 17043 | .is_comptime = parent_block.is_comptime, |
| 17030 | .body_len = 1, | 17044 | }; |
| 17031 | }), | | |
| 17032 | } }, | | |
| 17033 | }); | | |
| 17034 | sema.air_extra.appendAssumeCapacity(cond_br_inst); | | |
| 17035 | | 17045 | |
| 17036 | sema.air_instructions.appendAssumeCapacity(.{ | 17046 | defer fail_block.instructions.deinit(gpa); |
| 17037 | .tag = .cond_br, | | |
| 17038 | .data = .{ .pl_op = .{ | | |
| 17039 | .operand = ok, | | |
| 17040 | .payload = sema.addExtraAssumeCapacity(Air.CondBr{ | | |
| 17041 | .then_body_len = 1, | | |
| 17042 | .else_body_len = @intCast(u32, fail_block.instructions.items.len), | | |
| 17043 | }), | | |
| 17044 | } }, | | |
| 17045 | }); | | |
| 17046 | sema.air_extra.appendAssumeCapacity(br_inst); | | |
| 17047 | sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items); | | |
| 17048 | | 17047 | |
| 17049 | sema.air_instructions.appendAssumeCapacity(.{ | 17048 | { |
| 17050 | .tag = .br, | 17049 | const this_feature_is_implemented_in_the_backend = |
| 17051 | .data = .{ .br = .{ | 17050 | sema.mod.comp.bin_file.options.use_llvm; |
| 17052 | .block_inst = block_inst, | | |
| 17053 | .operand = .void_value, | | |
| 17054 | } }, | | |
| 17055 | }); | | |
| 17056 | | 17051 | |
| 17057 | parent_block.instructions.appendAssumeCapacity(block_inst); | 17052 | if (!this_feature_is_implemented_in_the_backend) { |
| | 17053 | // TODO implement this feature in all the backends and then delete this branch |
| | 17054 | _ = try fail_block.addNoOp(.breakpoint); |
| | 17055 | _ = try fail_block.addNoOp(.unreach); |
| | 17056 | } else { |
| | 17057 | const panic_fn = try sema.getBuiltin(&fail_block, src, "panicOutOfBounds"); |
| | 17058 | const args: [2]Air.Inst.Ref = .{ index, len }; |
| | 17059 | _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args); |
| | 17060 | } |
| | 17061 | } |
| | 17062 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); |
| 17058 | } | 17063 | } |
| 17059 | | 17064 | |
| 17060 | fn safetyPanic( | 17065 | fn safetyPanic( |
| ... | @@ -17069,7 +17074,6 @@ fn safetyPanic( | ... | @@ -17069,7 +17074,6 @@ fn safetyPanic( |
| 17069 | .cast_to_null => "cast causes pointer to be null", | 17074 | .cast_to_null => "cast causes pointer to be null", |
| 17070 | .incorrect_alignment => "incorrect alignment", | 17075 | .incorrect_alignment => "incorrect alignment", |
| 17071 | .invalid_error_code => "invalid error code", | 17076 | .invalid_error_code => "invalid error code", |
| 17072 | .index_out_of_bounds => "attempt to index out of bounds", | | |
| 17073 | .cast_truncated_data => "integer cast truncated bits", | 17077 | .cast_truncated_data => "integer cast truncated bits", |
| 17074 | .integer_overflow => "integer overflow", | 17078 | .integer_overflow => "integer overflow", |
| 17075 | .shl_overflow => "left shift overflowed bits", | 17079 | .shl_overflow => "left shift overflowed bits", |
| ... | @@ -18261,8 +18265,7 @@ fn elemValArray( | ... | @@ -18261,8 +18265,7 @@ fn elemValArray( |
| 18261 | if (maybe_index_val == null) { | 18265 | if (maybe_index_val == null) { |
| 18262 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); | 18266 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); |
| 18263 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; | 18267 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 18264 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); | 18268 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); |
| 18265 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); | | |
| 18266 | } | 18269 | } |
| 18267 | } | 18270 | } |
| 18268 | return block.addBinOp(.array_elem_val, array, elem_index); | 18271 | return block.addBinOp(.array_elem_val, array, elem_index); |
| ... | @@ -18317,8 +18320,7 @@ fn elemPtrArray( | ... | @@ -18317,8 +18320,7 @@ fn elemPtrArray( |
| 18317 | if (maybe_index_val == null) { | 18320 | if (maybe_index_val == null) { |
| 18318 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); | 18321 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); |
| 18319 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; | 18322 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 18320 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); | 18323 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); |
| 18321 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); | | |
| 18322 | } | 18324 | } |
| 18323 | } | 18325 | } |
| 18324 | return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); | 18326 | return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); |
| ... | @@ -18371,8 +18373,7 @@ fn elemValSlice( | ... | @@ -18371,8 +18373,7 @@ fn elemValSlice( |
| 18371 | else | 18373 | else |
| 18372 | try block.addTyOp(.slice_len, Type.usize, slice); | 18374 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 18373 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 18375 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 18374 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); | 18376 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); |
| 18375 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); | | |
| 18376 | } | 18377 | } |
| 18377 | try sema.queueFullTypeResolution(sema.typeOf(slice)); | 18378 | try sema.queueFullTypeResolution(sema.typeOf(slice)); |
| 18378 | return block.addBinOp(.slice_elem_val, slice, elem_index); | 18379 | return block.addBinOp(.slice_elem_val, slice, elem_index); |
| ... | @@ -18425,8 +18426,7 @@ fn elemPtrSlice( | ... | @@ -18425,8 +18426,7 @@ fn elemPtrSlice( |
| 18425 | break :len try block.addTyOp(.slice_len, Type.usize, slice); | 18426 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 18426 | }; | 18427 | }; |
| 18427 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 18428 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 18428 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); | 18429 | try sema.panicIndexOutOfBounds(block, elem_index_src, elem_index, len_inst, cmp_op); |
| 18429 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); | | |
| 18430 | } | 18430 | } |
| 18431 | return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); | 18431 | return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); |
| 18432 | } | 18432 | } |
| ... | @@ -21111,13 +21111,11 @@ fn analyzeSlice( | ... | @@ -21111,13 +21111,11 @@ fn analyzeSlice( |
| 21111 | break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src); | 21111 | break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src); |
| 21112 | } else null; | 21112 | } else null; |
| 21113 | if (opt_len_inst) |len_inst| { | 21113 | if (opt_len_inst) |len_inst| { |
| 21114 | const end_is_in_bounds = try block.addBinOp(.cmp_lte, end, len_inst); | 21114 | try sema.panicIndexOutOfBounds(block, src, end, len_inst, .cmp_lte); |
| 21115 | try sema.addSafetyCheck(block, end_is_in_bounds, .index_out_of_bounds); | | |
| 21116 | } | 21115 | } |
| 21117 | | 21116 | |
| 21118 | // requirement: start <= end | 21117 | // requirement: start <= end |
| 21119 | const start_is_in_bounds = try block.addBinOp(.cmp_lte, start, end); | 21118 | try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); |
| 21120 | try sema.addSafetyCheck(block, start_is_in_bounds, .index_out_of_bounds); | | |
| 21121 | } | 21119 | } |
| 21122 | return block.addInst(.{ | 21120 | return block.addInst(.{ |
| 21123 | .tag = .slice, | 21121 | .tag = .slice, |