| ... | ... | @@ -20148,6 +20148,77 @@ fn panicIndexOutOfBounds( |
| 20148 | 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 | 20222 | fn safetyPanic( |
| 20152 | 20223 | sema: *Sema, |
| 20153 | 20224 | block: *Block, |
| ... | ... | @@ -25368,6 +25439,7 @@ fn analyzeSlice( |
| 25368 | 25439 | } |
| 25369 | 25440 | break :s null; |
| 25370 | 25441 | }; |
| 25442 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 25371 | 25443 | |
| 25372 | 25444 | // requirement: start <= end |
| 25373 | 25445 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| ... | ... | @@ -25447,7 +25519,12 @@ fn analyzeSlice( |
| 25447 | 25519 | |
| 25448 | 25520 | const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); |
| 25449 | 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 | 25530 | if (!new_ptr_val.isUndef()) { |
| ... | ... | @@ -25511,7 +25588,7 @@ fn analyzeSlice( |
| 25511 | 25588 | // requirement: start <= end |
| 25512 | 25589 | try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); |
| 25513 | 25590 | } |
| 25514 | | return block.addInst(.{ |
| 25591 | const result = try block.addInst(.{ |
| 25515 | 25592 | .tag = .slice, |
| 25516 | 25593 | .data = .{ .ty_pl = .{ |
| 25517 | 25594 | .ty = try sema.addType(return_ty), |
| ... | ... | @@ -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 | 25608 | /// Asserts that lhs and rhs types are both numeric. |