authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-01 11:30:33+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-01 16:20:40+00:00
log5333d2443a80a82b34940be68e4ca8d1129b7ab7
tree49d430c90b50b7296638628635ac06665b58c3e3
parentd02c2c76fc718a4d55977cfa776c98dac1a90032

Sema: fix invalid coercion `*[n:x]T` -> `*[m]T` for `n != m`

The change in `Sema.coerceExtra` is just to avoid an unhelpful error message, covered by the added test case. Resolves: #22373

2 files changed, 73 insertions(+), 1 deletions(-)

src/Sema.zig+3-1
...@@ -29736,6 +29736,7 @@ fn coerceExtra(...@@ -29736,6 +29736,7 @@ fn coerceExtra(
29736 // Coercions where the source is a single pointer to an array.29736 // Coercions where the source is a single pointer to an array.
29737 src_array_ptr: {29737 src_array_ptr: {
29738 if (!inst_ty.isSinglePointer(zcu)) break :src_array_ptr;29738 if (!inst_ty.isSinglePointer(zcu)) break :src_array_ptr;
29739 if (dest_info.flags.size == .One) break :src_array_ptr; // `*[n]T` -> `*T` isn't valid
29739 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;29740 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
29740 const array_ty = inst_ty.childType(zcu);29741 const array_ty = inst_ty.childType(zcu);
29741 if (array_ty.zigTypeTag(zcu) != .array) break :src_array_ptr;29742 if (array_ty.zigTypeTag(zcu) != .array) break :src_array_ptr;
...@@ -29791,7 +29792,7 @@ fn coerceExtra(...@@ -29791,7 +29792,7 @@ fn coerceExtra(
29791 // *[N]T to [*]T29792 // *[N]T to [*]T
29792 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);29793 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
29793 },29794 },
29794 .One => {},29795 .One => unreachable, // early exit at top of block
29795 }29796 }
29796 }29797 }
2979729798
...@@ -31259,6 +31260,7 @@ fn coerceInMemoryAllowedPtrs(...@@ -31259,6 +31260,7 @@ fn coerceInMemoryAllowedPtrs(
31259 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.31260 // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice.
31260 // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes.31261 // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes.
31261 if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and31262 if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and
31263 src_child.arrayLen(zcu) == dest_child.arrayLen(zcu) and
31262 src_child.sentinel(zcu) != null and dest_child.sentinel(zcu) == null and31264 src_child.sentinel(zcu) != null and dest_child.sentinel(zcu) == null and
31263 .ok == try sema.coerceInMemoryAllowed(block, dest_child.childType(zcu), src_child.childType(zcu), !dest_info.flags.is_const, target, dest_src, src_src, null))31265 .ok == try sema.coerceInMemoryAllowed(block, dest_child.childType(zcu), src_child.childType(zcu), !dest_info.flags.is_const, target, dest_src, src_src, null))
31264 {31266 {
test/cases/compile_errors/coerce_array_to_different_size.zig created+70
...@@ -0,0 +1,70 @@
1export fn bigger(a: *const [10]u32) void {
2 const b: *const [20]u32 = a;
3 _ = b;
4}
5
6comptime {
7 const a: *const [10]u32 = &@splat(0);
8 const b: *const [20]u32 = a;
9 _ = b;
10}
11
12export fn biggerSentinel(a: *const [10:0]u32) void {
13 const b: *const [20]u32 = a;
14 _ = b;
15}
16
17comptime {
18 const a: *const [10:0]u32 = &@splat(0);
19 const b: *const [20]u32 = a;
20 _ = b;
21}
22
23export fn smaller(a: *const [10]u32) void {
24 const b: *const [5]u32 = a;
25 _ = b;
26}
27
28comptime {
29 const a: *const [10]u32 = &@splat(0);
30 const b: *const [5]u32 = a;
31 _ = b;
32}
33
34export fn smallerSentinel(a: *const [10:0]u32) void {
35 const b: *const [5]u32 = a;
36 _ = b;
37}
38
39comptime {
40 const a: *const [10:0]u32 = &@splat(0);
41 const b: *const [5]u32 = a;
42 _ = b;
43}
44
45// error
46//
47// :2:31: error: expected type '*const [20]u32', found '*const [10]u32'
48// :2:31: note: pointer type child '[10]u32' cannot cast into pointer type child '[20]u32'
49// :2:31: note: array of length 10 cannot cast into an array of length 20
50// :8:31: error: expected type '*const [20]u32', found '*const [10]u32'
51// :8:31: note: pointer type child '[10]u32' cannot cast into pointer type child '[20]u32'
52// :8:31: note: array of length 10 cannot cast into an array of length 20
53// :13:31: error: expected type '*const [20]u32', found '*const [10:0]u32'
54// :13:31: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[20]u32'
55// :13:31: note: array of length 10 cannot cast into an array of length 20
56// :19:31: error: expected type '*const [20]u32', found '*const [10:0]u32'
57// :19:31: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[20]u32'
58// :19:31: note: array of length 10 cannot cast into an array of length 20
59// :24:30: error: expected type '*const [5]u32', found '*const [10]u32'
60// :24:30: note: pointer type child '[10]u32' cannot cast into pointer type child '[5]u32'
61// :24:30: note: array of length 10 cannot cast into an array of length 5
62// :30:30: error: expected type '*const [5]u32', found '*const [10]u32'
63// :30:30: note: pointer type child '[10]u32' cannot cast into pointer type child '[5]u32'
64// :30:30: note: array of length 10 cannot cast into an array of length 5
65// :35:30: error: expected type '*const [5]u32', found '*const [10:0]u32'
66// :35:30: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[5]u32'
67// :35:30: note: array of length 10 cannot cast into an array of length 5
68// :41:30: error: expected type '*const [5]u32', found '*const [10:0]u32'
69// :41:30: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[5]u32'
70// :41:30: note: array of length 10 cannot cast into an array of length 5