Commit efc98fcbeb

Andrew Kelley <andrew@ziglang.org>
2024-09-24 23:31:00
disallow non-scalar sentinel types
see #17969
1 parent a40cdad
lib/std/builtin.zig
@@ -887,12 +887,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
     }
 }
 
-pub fn checkNonScalarSentinel(expected: anytype, actual: @TypeOf(expected)) void {
-    if (!std.meta.eql(expected, actual)) {
-        panicSentinelMismatch(expected, actual);
-    }
-}
-
 pub fn panicSentinelMismatch(expected: anytype, actual: @TypeOf(expected)) noreturn {
     @branchHint(.cold);
     std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{ expected, actual });
src/Sema.zig
@@ -19741,6 +19741,14 @@ fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !voi
     return sema.failWithExpectedOptionalType(block, src, ty);
 }
 
+fn checkSentinelType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+    const pt = sema.pt;
+    const zcu = pt.zcu;
+    if (!ty.isSelfComparable(zcu, true)) {
+        return sema.fail(block, src, "non-scalar sentinel type '{}'", .{ty.fmt(pt)});
+    }
+}
+
 fn zirIsNonNull(
     sema: *Sema,
     block: *Block,
@@ -20542,6 +20550,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
         const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{
             .needed_comptime_reason = "pointer sentinel value must be comptime-known",
         });
+        try checkSentinelType(sema, block, sentinel_src, elem_ty);
         break :blk val.toIntern();
     } else .none;
 
@@ -28114,13 +28123,9 @@ fn panicSentinelMismatch(
                 .operation = .And,
             } },
         });
-    } else if (sentinel_ty.isSelfComparable(zcu, true))
-        try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
-    else {
-        const panic_fn = try pt.getBuiltin("checkNonScalarSentinel");
-        const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
-        try sema.callBuiltin(parent_block, src, panic_fn, .auto, &args, .@"safety check");
-        return;
+    } else ok: {
+        assert(sentinel_ty.isSelfComparable(zcu, true));
+        break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
     };
 
     if (!pt.zcu.comp.formatted_panics) {
@@ -33573,6 +33578,7 @@ fn analyzeSlice(
     const sentinel = s: {
         if (sentinel_opt != .none) {
             const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
+            try checkSentinelType(sema, block, sentinel_src, elem_ty);
             break :s try sema.resolveConstDefinedValue(block, sentinel_src, casted, .{
                 .needed_comptime_reason = "slice sentinel must be comptime-known",
             });
test/cases/compile_errors/array slice sentinel mismatch non-scalar.zig
@@ -0,0 +1,13 @@
+export fn foo() void {
+    const S = struct { a: u32 };
+    var arr = [_]S{ .{ .a = 1 }, .{ .a = 2 } };
+    const s = arr[0..1 :.{ .a = 1 }];
+    _ = s;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :4:26: error: non-scalar sentinel type 'tmp.foo.S'
+// :2:15: note: struct declared here
test/cases/safety/array slice sentinel mismatch non-scalar.zig
@@ -1,21 +0,0 @@
-const std = @import("std");
-
-pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
-    _ = stack_trace;
-    if (std.mem.eql(u8, message, "sentinel mismatch: expected tmp.main.S{ .a = 1 }, found tmp.main.S{ .a = 2 }")) {
-        std.process.exit(0);
-    }
-    std.process.exit(1);
-}
-
-pub fn main() !void {
-    const S = struct { a: u32 };
-    var arr = [_]S{ .{ .a = 1 }, .{ .a = 2 } };
-    const s = arr[0..1 :.{ .a = 1 }];
-    _ = s;
-    return error.TestFailed;
-}
-
-// run
-// backend=llvm
-// target=native