| author | |
| committer | |
| log | d53cc5e5b2ac51793ea19a847d8cee409af1dee3 |
| tree | e60cee6a989fd62a64d93d9acdc19729f4c44ed7 |
| parent | 0bdc0bb534ed6d3cc787b5bca44173d2b49480da |
This is actually completely well-defined. The resulting slice always has
0 elements. The only disallowed case is casting *to* a slice of a
zero-bit type, because in that case, you cna't figure out how many
destination elements to use (and there's *no* valid destination length
if the source slice corresponds to more than 0 bits).2 files changed, 25 insertions(+), 2 deletions(-)
src/Sema.zig+5-2| ... | @@ -22837,11 +22837,14 @@ fn ptrCastFull( | ... | @@ -22837,11 +22837,14 @@ fn ptrCastFull( |
| 22837 | if (src_slice_like_elem.comptimeOnly(zcu) or dest_elem.comptimeOnly(zcu)) { | 22837 | if (src_slice_like_elem.comptimeOnly(zcu) or dest_elem.comptimeOnly(zcu)) { |
| 22838 | return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) }); | 22838 | return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) }); |
| 22839 | } | 22839 | } |
| 22840 | const src_elem_size = src_slice_like_elem.abiSize(zcu); | 22840 | // It's okay for `src_slice_like_elem` to be 0-bit; the resulting slice will just always have 0 elements. |
| 22841 | // However, `dest_elem` can't be 0-bit. If it were, then either the source slice has 0 bits and we don't | ||
| 22842 | // know how what `result.len` should be, or the source has >0 bits and there is no valid `result.len`. | ||
| 22841 | const dest_elem_size = dest_elem.abiSize(zcu); | 22843 | const dest_elem_size = dest_elem.abiSize(zcu); |
| 22842 | if (src_elem_size == 0 or dest_elem_size == 0) { | 22844 | if (dest_elem_size == 0) { |
| 22843 | return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) }); | 22845 | return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) }); |
| 22844 | } | 22846 | } |
| 22847 | const src_elem_size = src_slice_like_elem.abiSize(zcu); | ||
| 22845 | break :need_len_change src_elem_size != dest_elem_size; | 22848 | break :need_len_change src_elem_size != dest_elem_size; |
| 22846 | } else false; | 22849 | } else false; |
| 22847 | 22850 |
test/behavior/ptrcast.zig+20| ... | @@ -507,3 +507,23 @@ test "@ptrCast array pointer to slice with complex length decrease" { | ... | @@ -507,3 +507,23 @@ test "@ptrCast array pointer to slice with complex length decrease" { |
| 507 | try S.doTheTest(@splat(0)); | 507 | try S.doTheTest(@splat(0)); |
| 508 | try comptime S.doTheTest(@splat(0)); | 508 | try comptime S.doTheTest(@splat(0)); |
| 509 | } | 509 | } |
| 510 | |||
| 511 | test "@ptrCast slice of zero-bit type to different slice" { | ||
| 512 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 513 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 515 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 516 | |||
| 517 | const S = struct { | ||
| 518 | fn doTheTest(comptime T: type, zero_bits: []const T) !void { | ||
| 519 | const out: []const u8 = @ptrCast(zero_bits); | ||
| 520 | try expect(out.len == 0); | ||
| 521 | } | ||
| 522 | }; | ||
| 523 | try S.doTheTest(void, &.{ {}, {}, {} }); | ||
| 524 | try S.doTheTest(u0, &.{ 0, 0, 0, 0 }); | ||
| 525 | try S.doTheTest(packed struct(u0) {}, &.{ .{}, .{} }); | ||
| 526 | try comptime S.doTheTest(void, &.{ {}, {}, {} }); | ||
| 527 | try comptime S.doTheTest(u0, &.{ 0, 0, 0, 0 }); | ||
| 528 | try comptime S.doTheTest(packed struct(u0) {}, &.{ .{}, .{} }); | ||
| 529 | } |