diff --git a/src/Sema.zig b/src/Sema.zig index 191ab3407093..390ec0b92627 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29385,14 +29385,18 @@ const InMemoryCoercionResult = union(enum) { break; }, .array_sentinel => |sentinel| { - if (sentinel.actual.toIntern() != .unreachable_value) { - try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{ - sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), + if (sentinel.wanted.toIntern() == .unreachable_value) { + try sema.errNote(src, msg, "source array cannot be guaranteed to maintain '{f}' sentinel", .{ + sentinel.actual.fmtValueSema(pt, sema), }); - } else { + } else if (sentinel.actual.toIntern() == .unreachable_value) { try sema.errNote(src, msg, "destination array requires '{f}' sentinel", .{ sentinel.wanted.fmtValueSema(pt, sema), }); + } else { + try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{ + sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), + }); } break; }, @@ -30179,10 +30183,14 @@ fn coerceInMemoryAllowedPtrs( src_src, null, ); - if (child != .ok and !dest_is_mut) allow: { + if (child != .ok) allow: { // 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 + // + // We must once again include `dest_is_mut` because `**[n:s]T -> **[n]T` + // is not allowed, as it would make it possible to assign an illegal value + // to the sentinel-terminated side. + if (!dest_is_mut and 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_pointers_with_uncoercable_child_pointers.zig b/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig new file mode 100644 index 000000000000..bef21b2777ff --- /dev/null +++ b/test/cases/compile_errors/coerce_pointers_with_uncoercable_child_pointers.zig @@ -0,0 +1,52 @@ +export fn entry1() void { + const p: **u32 = undefined; + const q: **i32 = p; + _ = q; +} + +export fn entry2() void { + const p: [*]*u32 = undefined; + const q: [*]*i32 = p; + _ = q; +} + +export fn entry3() void { + const p: []*u32 = undefined; + const q: []*i32 = p; + _ = q; +} + +export fn entry4() void { + const p: [*c]*u32 = undefined; + const q: [*c]*i32 = p; + _ = q; +} + +export fn entry5() void { + const p: **[1:42]u8 = undefined; + const q: **[1]u8 = p; + _ = q; +} + +// error +// +// :3:22: error: expected type '**i32', found '**u32' +// :3:22: note: pointer type child '*u32' cannot cast into pointer type child '*i32' +// :3:22: note: pointer type child 'u32' cannot cast into pointer type child 'i32' +// :3:22: note: signed 32-bit int cannot represent all possible unsigned 32-bit values +// :9:24: error: expected type '[*]*i32', found '[*]*u32' +// :9:24: note: pointer type child '*u32' cannot cast into pointer type child '*i32' +// :9:24: note: pointer type child 'u32' cannot cast into pointer type child 'i32' +// :9:24: note: signed 32-bit int cannot represent all possible unsigned 32-bit values +// :15:23: error: expected type '[]*i32', found '[]*u32' +// :15:23: note: pointer type child '*u32' cannot cast into pointer type child '*i32' +// :15:23: note: pointer type child 'u32' cannot cast into pointer type child 'i32' +// :15:23: note: signed 32-bit int cannot represent all possible unsigned 32-bit values +// :21:25: error: expected type '[*c]*i32', found '[*c]*u32' +// :21:25: note: pointer type child '*u32' cannot cast into pointer type child '*i32' +// :21:25: note: pointer type child 'u32' cannot cast into pointer type child 'i32' +// :21:25: note: signed 32-bit int cannot represent all possible unsigned 32-bit values +// :27:24: error: expected type '**[1]u8', found '**[1:42]u8' +// :27:24: note: pointer type child '*[1:42]u8' cannot cast into pointer type child '*[1]u8' +// :27:24: note: pointer type child '[1:42]u8' cannot cast into pointer type child '[1]u8' +// :27:24: note: source array cannot be guaranteed to maintain '42' sentinel