authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2025-11-14 14:13:09+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-11-14 23:25:54+00:00
log06d08dababda8fde2fef8267698a712d1966045d
tree2517a590fd472799ebea1eee4f39cf92de023230
parentc6b5945356568f6ec70ca00f9a844bd180f8ca62

Sema: fix illegal multi level pointer coercions

Moves a premature check that allowed pointers to mutable pointers to coerce to any other pointer to a mutable pointer.

2 files changed, 66 insertions(+), 6 deletions(-)

src/Sema.zig+14-6
......@@ -29385,14 +29385,18 @@ const InMemoryCoercionResult = union(enum) {
2938529385 break;
2938629386 },
2938729387 .array_sentinel => |sentinel| {
29388 if (sentinel.actual.toIntern() != .unreachable_value) {
29389 try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{
29390 sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema),
29388 if (sentinel.wanted.toIntern() == .unreachable_value) {
29389 try sema.errNote(src, msg, "source array cannot be guaranteed to maintain '{f}' sentinel", .{
29390 sentinel.actual.fmtValueSema(pt, sema),
2939129391 });
29392 } else {
29392 } else if (sentinel.actual.toIntern() == .unreachable_value) {
2939329393 try sema.errNote(src, msg, "destination array requires '{f}' sentinel", .{
2939429394 sentinel.wanted.fmtValueSema(pt, sema),
2939529395 });
29396 } else {
29397 try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{
29398 sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema),
29399 });
2939629400 }
2939729401 break;
2939829402 },
......@@ -30179,10 +30183,14 @@ fn coerceInMemoryAllowedPtrs(
3017930183 src_src,
3018030184 null,
3018130185 );
30182 if (child != .ok and !dest_is_mut) allow: {
30186 if (child != .ok) allow: {
3018330187 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.
3018430188 // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes.
30185 if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and
30189 //
30190 // We must once again include `dest_is_mut` because `**[n:s]T -> **[n]T`
30191 // is not allowed, as it would make it possible to assign an illegal value
30192 // to the sentinel-terminated side.
30193 if (!dest_is_mut and src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and
3018630194 src_child.arrayLen(zcu) == dest_child.arrayLen(zcu) and
3018730195 src_child.sentinel(zcu) != null and dest_child.sentinel(zcu) == null and
3018830196 .ok == try sema.coerceInMemoryAllowed(block, dest_child.childType(zcu), src_child.childType(zcu), !dest_info.flags.is_const, target, dest_src, src_src, null))
test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig created+52
......@@ -0,0 +1,52 @@
1export fn entry1() void {
2 const p: **u32 = undefined;
3 const q: **i32 = p;
4 _ = q;
5}
6
7export fn entry2() void {
8 const p: [*]*u32 = undefined;
9 const q: [*]*i32 = p;
10 _ = q;
11}
12
13export fn entry3() void {
14 const p: []*u32 = undefined;
15 const q: []*i32 = p;
16 _ = q;
17}
18
19export fn entry4() void {
20 const p: [*c]*u32 = undefined;
21 const q: [*c]*i32 = p;
22 _ = q;
23}
24
25export fn entry5() void {
26 const p: **[1:42]u8 = undefined;
27 const q: **[1]u8 = p;
28 _ = q;
29}
30
31// error
32//
33// :3:22: error: expected type '**i32', found '**u32'
34// :3:22: note: pointer type child '*u32' cannot cast into pointer type child '*i32'
35// :3:22: note: pointer type child 'u32' cannot cast into pointer type child 'i32'
36// :3:22: note: signed 32-bit int cannot represent all possible unsigned 32-bit values
37// :9:24: error: expected type '[*]*i32', found '[*]*u32'
38// :9:24: note: pointer type child '*u32' cannot cast into pointer type child '*i32'
39// :9:24: note: pointer type child 'u32' cannot cast into pointer type child 'i32'
40// :9:24: note: signed 32-bit int cannot represent all possible unsigned 32-bit values
41// :15:23: error: expected type '[]*i32', found '[]*u32'
42// :15:23: note: pointer type child '*u32' cannot cast into pointer type child '*i32'
43// :15:23: note: pointer type child 'u32' cannot cast into pointer type child 'i32'
44// :15:23: note: signed 32-bit int cannot represent all possible unsigned 32-bit values
45// :21:25: error: expected type '[*c]*i32', found '[*c]*u32'
46// :21:25: note: pointer type child '*u32' cannot cast into pointer type child '*i32'
47// :21:25: note: pointer type child 'u32' cannot cast into pointer type child 'i32'
48// :21:25: note: signed 32-bit int cannot represent all possible unsigned 32-bit values
49// :27:24: error: expected type '**[1]u8', found '**[1:42]u8'
50// :27:24: note: pointer type child '*[1:42]u8' cannot cast into pointer type child '*[1]u8'
51// :27:24: note: pointer type child '[1:42]u8' cannot cast into pointer type child '[1]u8'
52// :27:24: note: source array cannot be guaranteed to maintain '42' sentinel