| ... | @@ -20148,6 +20148,77 @@ fn panicIndexOutOfBounds( | ... | @@ -20148,6 +20148,77 @@ fn panicIndexOutOfBounds( |
| 20148 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); | 20148 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); |
| 20149 | } | 20149 | } |
| 20150 | | 20150 | |
| | 20151 | fn panicSentinelMismatch( |
| | 20152 | sema: *Sema, |
| | 20153 | parent_block: *Block, |
| | 20154 | src: LazySrcLoc, |
| | 20155 | maybe_sentinel: ?Value, |
| | 20156 | sentinel_ty: Type, |
| | 20157 | ptr: Air.Inst.Ref, |
| | 20158 | sentinel_index: Air.Inst.Ref, |
| | 20159 | ) !void { |
| | 20160 | const expected_sentinel_val = maybe_sentinel orelse return; |
| | 20161 | const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); |
| | 20162 | |
| | 20163 | const ptr_ty = sema.typeOf(ptr); |
| | 20164 | const actual_sentinel = if (ptr_ty.isSlice()) |
| | 20165 | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) |
| | 20166 | else blk: { |
| | 20167 | const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); |
| | 20168 | const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty); |
| | 20169 | break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); |
| | 20170 | }; |
| | 20171 | |
| | 20172 | const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: { |
| | 20173 | const eql = |
| | 20174 | try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq, try sema.addType(sentinel_ty)); |
| | 20175 | break :ok try parent_block.addInst(.{ |
| | 20176 | .tag = .reduce, |
| | 20177 | .data = .{ .reduce = .{ |
| | 20178 | .operand = eql, |
| | 20179 | .operation = .And, |
| | 20180 | } }, |
| | 20181 | }); |
| | 20182 | } else if (sentinel_ty.isSelfComparable(true)) |
| | 20183 | try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) |
| | 20184 | else { |
| | 20185 | const panic_fn = try sema.getBuiltin(parent_block, src, "checkNonScalarSentinel"); |
| | 20186 | const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; |
| | 20187 | _ = try sema.analyzeCall(parent_block, panic_fn, src, src, .auto, false, &args, null); |
| | 20188 | return; |
| | 20189 | }; |
| | 20190 | const gpa = sema.gpa; |
| | 20191 | |
| | 20192 | var fail_block: Block = .{ |
| | 20193 | .parent = parent_block, |
| | 20194 | .sema = sema, |
| | 20195 | .src_decl = parent_block.src_decl, |
| | 20196 | .namespace = parent_block.namespace, |
| | 20197 | .wip_capture_scope = parent_block.wip_capture_scope, |
| | 20198 | .instructions = .{}, |
| | 20199 | .inlining = parent_block.inlining, |
| | 20200 | .is_comptime = parent_block.is_comptime, |
| | 20201 | }; |
| | 20202 | |
| | 20203 | defer fail_block.instructions.deinit(gpa); |
| | 20204 | |
| | 20205 | { |
| | 20206 | const this_feature_is_implemented_in_the_backend = |
| | 20207 | sema.mod.comp.bin_file.options.use_llvm; |
| | 20208 | |
| | 20209 | if (!this_feature_is_implemented_in_the_backend) { |
| | 20210 | // TODO implement this feature in all the backends and then delete this branch |
| | 20211 | _ = try fail_block.addNoOp(.breakpoint); |
| | 20212 | _ = try fail_block.addNoOp(.unreach); |
| | 20213 | } else { |
| | 20214 | const panic_fn = try sema.getBuiltin(&fail_block, src, "panicSentinelMismatch"); |
| | 20215 | const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel }; |
| | 20216 | _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null); |
| | 20217 | } |
| | 20218 | } |
| | 20219 | try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); |
| | 20220 | } |
| | 20221 | |
| 20151 | fn safetyPanic( | 20222 | fn safetyPanic( |
| 20152 | sema: *Sema, | 20223 | sema: *Sema, |
| 20153 | block: *Block, | 20224 | block: *Block, |
| ... | @@ -25368,6 +25439,7 @@ fn analyzeSlice( | ... | @@ -25368,6 +25439,7 @@ fn analyzeSlice( |
| 25368 | } | 25439 | } |
| 25369 | break :s null; | 25440 | break :s null; |
| 25370 | }; | 25441 | }; |
| | 25442 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 25371 | | 25443 | |
| 25372 | // requirement: start <= end | 25444 | // requirement: start <= end |
| 25373 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { | 25445 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| ... | @@ -25447,7 +25519,12 @@ fn analyzeSlice( | ... | @@ -25447,7 +25519,12 @@ fn analyzeSlice( |
| 25447 | | 25519 | |
| 25448 | const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); | 25520 | const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); |
| 25449 | const new_ptr_val = opt_new_ptr_val orelse { | 25521 | const new_ptr_val = opt_new_ptr_val orelse { |
| 25450 | return block.addBitCast(return_ty, new_ptr); | 25522 | const result = try block.addBitCast(return_ty, new_ptr); |
| | 25523 | if (block.wantSafety()) { |
| | 25524 | // requirement: result[new_len] == slice_sentinel |
| | 25525 | try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); |
| | 25526 | } |
| | 25527 | return result; |
| 25451 | }; | 25528 | }; |
| 25452 | | 25529 | |
| 25453 | if (!new_ptr_val.isUndef()) { | 25530 | if (!new_ptr_val.isUndef()) { |
| ... | @@ -25511,7 +25588,7 @@ fn analyzeSlice( | ... | @@ -25511,7 +25588,7 @@ fn analyzeSlice( |
| 25511 | // requirement: start <= end | 25588 | // requirement: start <= end |
| 25512 | try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); | 25589 | try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); |
| 25513 | } | 25590 | } |
| 25514 | return block.addInst(.{ | 25591 | const result = try block.addInst(.{ |
| 25515 | .tag = .slice, | 25592 | .tag = .slice, |
| 25516 | .data = .{ .ty_pl = .{ | 25593 | .data = .{ .ty_pl = .{ |
| 25517 | .ty = try sema.addType(return_ty), | 25594 | .ty = try sema.addType(return_ty), |
| ... | @@ -25521,6 +25598,11 @@ fn analyzeSlice( | ... | @@ -25521,6 +25598,11 @@ fn analyzeSlice( |
| 25521 | }), | 25598 | }), |
| 25522 | } }, | 25599 | } }, |
| 25523 | }); | 25600 | }); |
| | 25601 | if (block.wantSafety()) { |
| | 25602 | // requirement: result[new_len] == slice_sentinel |
| | 25603 | try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); |
| | 25604 | } |
| | 25605 | return result; |
| 25524 | } | 25606 | } |
| 25525 | | 25607 | |
| 25526 | /// Asserts that lhs and rhs types are both numeric. | 25608 | /// Asserts that lhs and rhs types are both numeric. |