aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-08-01 19:33:18 +0300
committerVeikka Tuominen <git@vexu.eu>2022-08-02 18:34:30 +0300
commit14f0b70570aa1c50c7316851293899000615bc94 (patch)
treeff1677912bc9d33137a5d3ffc0b1ba63a61138cb /src/Sema.zig
parent292906fb2378bd37e02abf09e2be7f86ee657fac (diff)
downloadzig-14f0b70570aa1c50c7316851293899000615bc94.tar.gz
zig-14f0b70570aa1c50c7316851293899000615bc94.zip
Sema: add safety for sentinel slice
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig86
1 files changed, 84 insertions, 2 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 67f04daf83..e41602a037 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -20148,6 +20148,77 @@ fn panicIndexOutOfBounds(
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
}
+fn panicSentinelMismatch(
+ sema: *Sema,
+ parent_block: *Block,
+ src: LazySrcLoc,
+ maybe_sentinel: ?Value,
+ sentinel_ty: Type,
+ ptr: Air.Inst.Ref,
+ sentinel_index: Air.Inst.Ref,
+) !void {
+ const expected_sentinel_val = maybe_sentinel orelse return;
+ const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
+
+ const ptr_ty = sema.typeOf(ptr);
+ const actual_sentinel = if (ptr_ty.isSlice())
+ try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
+ else blk: {
+ const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
+ const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
+ break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
+ };
+
+ const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: {
+ const eql =
+ try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq, try sema.addType(sentinel_ty));
+ break :ok try parent_block.addInst(.{
+ .tag = .reduce,
+ .data = .{ .reduce = .{
+ .operand = eql,
+ .operation = .And,
+ } },
+ });
+ } else if (sentinel_ty.isSelfComparable(true))
+ try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
+ else {
+ const panic_fn = try sema.getBuiltin(parent_block, src, "checkNonScalarSentinel");
+ const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
+ _ = try sema.analyzeCall(parent_block, panic_fn, src, src, .auto, false, &args, null);
+ return;
+ };
+ const gpa = sema.gpa;
+
+ var fail_block: Block = .{
+ .parent = parent_block,
+ .sema = sema,
+ .src_decl = parent_block.src_decl,
+ .namespace = parent_block.namespace,
+ .wip_capture_scope = parent_block.wip_capture_scope,
+ .instructions = .{},
+ .inlining = parent_block.inlining,
+ .is_comptime = parent_block.is_comptime,
+ };
+
+ defer fail_block.instructions.deinit(gpa);
+
+ {
+ const this_feature_is_implemented_in_the_backend =
+ sema.mod.comp.bin_file.options.use_llvm;
+
+ if (!this_feature_is_implemented_in_the_backend) {
+ // TODO implement this feature in all the backends and then delete this branch
+ _ = try fail_block.addNoOp(.breakpoint);
+ _ = try fail_block.addNoOp(.unreach);
+ } else {
+ const panic_fn = try sema.getBuiltin(&fail_block, src, "panicSentinelMismatch");
+ const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
+ _ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null);
+ }
+ }
+ try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
+}
+
fn safetyPanic(
sema: *Sema,
block: *Block,
@@ -25368,6 +25439,7 @@ fn analyzeSlice(
}
break :s null;
};
+ const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
// requirement: start <= end
if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
@@ -25447,7 +25519,12 @@ fn analyzeSlice(
const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr);
const new_ptr_val = opt_new_ptr_val orelse {
- return block.addBitCast(return_ty, new_ptr);
+ const result = try block.addBitCast(return_ty, new_ptr);
+ if (block.wantSafety()) {
+ // requirement: result[new_len] == slice_sentinel
+ try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
+ }
+ return result;
};
if (!new_ptr_val.isUndef()) {
@@ -25511,7 +25588,7 @@ fn analyzeSlice(
// requirement: start <= end
try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte);
}
- return block.addInst(.{
+ const result = try block.addInst(.{
.tag = .slice,
.data = .{ .ty_pl = .{
.ty = try sema.addType(return_ty),
@@ -25521,6 +25598,11 @@ fn analyzeSlice(
}),
} },
});
+ if (block.wantSafety()) {
+ // requirement: result[new_len] == slice_sentinel
+ try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
+ }
+ return result;
}
/// Asserts that lhs and rhs types are both numeric.