From 18cdc4f9d48f5dea8e3f3fd2abdd86bf3b6e56ad Mon Sep 17 00:00:00 2001 From: mlugg Date: Wed, 1 Jan 2025 11:30:33 +0000 Subject: [PATCH] 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 --- src/Sema.zig | 4 +- .../coerce_array_to_different_size.zig | 70 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/cases/compile_errors/coerce_array_to_different_size.zig diff --git a/src/Sema.zig b/src/Sema.zig index 32c4134d9bb7..19f80e24c663 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29736,6 +29736,7 @@ fn coerceExtra( // Coercions where the source is a single pointer to an array. src_array_ptr: { if (!inst_ty.isSinglePointer(zcu)) break :src_array_ptr; + if (dest_info.flags.size == .One) break :src_array_ptr; // `*[n]T` -> `*T` isn't valid if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; const array_ty = inst_ty.childType(zcu); if (array_ty.zigTypeTag(zcu) != .array) break :src_array_ptr; @@ -29791,7 +29792,7 @@ fn coerceExtra( // *[N]T to [*]T return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); }, - .One => {}, + .One => unreachable, // early exit at top of block } } @@ -31259,6 +31260,7 @@ fn coerceInMemoryAllowedPtrs( // As a special case, we also allow coercing `*[n:s]T` to `*[n]T`, akin to dropping the sentinel from a slice. // `*[n:s]T` cannot coerce in memory to `*[n]T` since they have different sizes. if (src_child.zigTypeTag(zcu) == .array and dest_child.zigTypeTag(zcu) == .array and + src_child.arrayLen(zcu) == dest_child.arrayLen(zcu) and src_child.sentinel(zcu) != null and dest_child.sentinel(zcu) == null and .ok == try sema.coerceInMemoryAllowed(block, dest_child.childType(zcu), src_child.childType(zcu), !dest_info.flags.is_const, target, dest_src, src_src, null)) { diff --git a/test/cases/compile_errors/coerce_array_to_different_size.zig b/test/cases/compile_errors/coerce_array_to_different_size.zig new file mode 100644 index 000000000000..58edd3a0228e --- /dev/null +++ b/test/cases/compile_errors/coerce_array_to_different_size.zig @@ -0,0 +1,70 @@ +export fn bigger(a: *const [10]u32) void { + const b: *const [20]u32 = a; + _ = b; +} + +comptime { + const a: *const [10]u32 = &@splat(0); + const b: *const [20]u32 = a; + _ = b; +} + +export fn biggerSentinel(a: *const [10:0]u32) void { + const b: *const [20]u32 = a; + _ = b; +} + +comptime { + const a: *const [10:0]u32 = &@splat(0); + const b: *const [20]u32 = a; + _ = b; +} + +export fn smaller(a: *const [10]u32) void { + const b: *const [5]u32 = a; + _ = b; +} + +comptime { + const a: *const [10]u32 = &@splat(0); + const b: *const [5]u32 = a; + _ = b; +} + +export fn smallerSentinel(a: *const [10:0]u32) void { + const b: *const [5]u32 = a; + _ = b; +} + +comptime { + const a: *const [10:0]u32 = &@splat(0); + const b: *const [5]u32 = a; + _ = b; +} + +// error +// +// :2:31: error: expected type '*const [20]u32', found '*const [10]u32' +// :2:31: note: pointer type child '[10]u32' cannot cast into pointer type child '[20]u32' +// :2:31: note: array of length 10 cannot cast into an array of length 20 +// :8:31: error: expected type '*const [20]u32', found '*const [10]u32' +// :8:31: note: pointer type child '[10]u32' cannot cast into pointer type child '[20]u32' +// :8:31: note: array of length 10 cannot cast into an array of length 20 +// :13:31: error: expected type '*const [20]u32', found '*const [10:0]u32' +// :13:31: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[20]u32' +// :13:31: note: array of length 10 cannot cast into an array of length 20 +// :19:31: error: expected type '*const [20]u32', found '*const [10:0]u32' +// :19:31: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[20]u32' +// :19:31: note: array of length 10 cannot cast into an array of length 20 +// :24:30: error: expected type '*const [5]u32', found '*const [10]u32' +// :24:30: note: pointer type child '[10]u32' cannot cast into pointer type child '[5]u32' +// :24:30: note: array of length 10 cannot cast into an array of length 5 +// :30:30: error: expected type '*const [5]u32', found '*const [10]u32' +// :30:30: note: pointer type child '[10]u32' cannot cast into pointer type child '[5]u32' +// :30:30: note: array of length 10 cannot cast into an array of length 5 +// :35:30: error: expected type '*const [5]u32', found '*const [10:0]u32' +// :35:30: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[5]u32' +// :35:30: note: array of length 10 cannot cast into an array of length 5 +// :41:30: error: expected type '*const [5]u32', found '*const [10:0]u32' +// :41:30: note: pointer type child '[10:0]u32' cannot cast into pointer type child '[5]u32' +// :41:30: note: array of length 10 cannot cast into an array of length 5