authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2024-12-31 16:07:08+11:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-07-31 12:02:19+01:00
log19fc5f4fb29a525252b2eaf3f6388d07f97bd32f
tree2ef144edec2325d943ab8601c686aaab4ebacae5
parentbce6a7c21529e9b294a641b5d7472c000204aaef

Sema: disallow slicing many-item pointer with different sentinel

This change prevents adding or changing the sentinel in the type of a many-item pointer via the slicing syntax `ptr[a.. :S]`.

3 files changed, 50 insertions(+), 3 deletions(-)

src/Sema.zig+32
...@@ -31876,6 +31876,38 @@ fn analyzeSlice(...@@ -31876,6 +31876,38 @@ fn analyzeSlice(
31876 break :e try sema.coerce(block, .usize, uncasted_end, end_src);31876 break :e try sema.coerce(block, .usize, uncasted_end, end_src);
31877 } else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);31877 } else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);
31878 }31878 }
31879
31880 // when slicing a many-item pointer, if a sentinel `S` is provided as in `ptr[a.. :S]`, it
31881 // must match the sentinel of `@TypeOf(ptr)`.
31882 sentinel_check: {
31883 if (sentinel_opt == .none) break :sentinel_check;
31884 const provided = provided: {
31885 const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
31886 try checkSentinelType(sema, block, sentinel_src, elem_ty);
31887 break :provided try sema.resolveConstDefinedValue(
31888 block,
31889 sentinel_src,
31890 casted,
31891 .{ .simple = .slice_sentinel },
31892 );
31893 };
31894
31895 if (ptr_sentinel) |current| {
31896 if (provided.toIntern() == current.toIntern()) break :sentinel_check;
31897 }
31898
31899 return sema.failWithOwnedErrorMsg(block, msg: {
31900 const msg = try sema.errMsg(sentinel_src, "sentinel-terminated slicing of many-item pointer must match existing sentinel", .{});
31901 errdefer msg.destroy(sema.gpa);
31902 if (ptr_sentinel) |current| {
31903 try sema.errNote(sentinel_src, msg, "expected sentinel '{f}', found '{f}'", .{ current.fmtValue(pt), provided.fmtValue(pt) });
31904 } else {
31905 try sema.errNote(ptr_src, msg, "type '{f}' does not have a sentinel", .{slice_ty.fmt(pt)});
31906 }
31907 try sema.errNote(src, msg, "use @ptrCast to cast pointer sentinel", .{});
31908 break :msg msg;
31909 });
31910 }
31879 return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);31911 return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
31880 };31912 };
3188131913
test/behavior/slice.zig-3
...@@ -628,9 +628,6 @@ test "slice syntax resulting in pointer-to-array" {...@@ -628,9 +628,6 @@ test "slice syntax resulting in pointer-to-array" {
628 comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);628 comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);
629 comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);629 comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);
630 comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8);630 comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8);
631 comptime assert(@TypeOf(ptr[1.. :0][0..2]) == *[2]u8);
632 comptime assert(@TypeOf(ptr[1.. :0][0..4]) == *[4]u8);
633 comptime assert(@TypeOf(ptr[1.. :0][0..2 :4]) == *[2:4]u8);
634631
635 var ptr_z: [*:0]u8 = &array;632 var ptr_z: [*:0]u8 = &array;
636 comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);633 comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);
test/cases/compile_errors/slice_of_many-item_pointer_preserves_sentinel.zig created+18
...@@ -0,0 +1,18 @@
1comptime {
2 var ptr: [*]const u8 = undefined;
3 _ = ptr[0.. :0];
4}
5
6comptime {
7 var ptrz: [*:0]const u8 = undefined;
8 _ = ptrz[0.. :1];
9}
10
11// error
12//
13// :3:18: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
14// :3:9: note: type '[*]const u8' does not have a sentinel
15// :3:12: note: use @ptrCast to cast pointer sentinel
16// :8:19: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
17// :8:19: note: expected sentinel '0', found '1'
18// :8:13: note: use @ptrCast to cast pointer sentinel