Skip to content

Commit d53cc5e

Browse files
mluggandrewrk
authored andcommitted
Sema: allow @ptrCast slice of zero-bit type to slice of non-zero-bit type
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).
1 parent 0bdc0bb commit d53cc5e

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

src/Sema.zig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22837,11 +22837,14 @@ fn ptrCastFull(
2283722837
if (src_slice_like_elem.comptimeOnly(zcu) or dest_elem.comptimeOnly(zcu)) {
2283822838
return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) });
2283922839
}
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`.
2284122843
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) {
2284322845
return sema.fail(block, src, "cannot infer length of slice of '{}' from slice of '{}'", .{ dest_elem.fmt(pt), src_slice_like_elem.fmt(pt) });
2284422846
}
22847+
const src_elem_size = src_slice_like_elem.abiSize(zcu);
2284522848
break :need_len_change src_elem_size != dest_elem_size;
2284622849
} else false;
2284722850

test/behavior/ptrcast.zig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,23 @@ test "@ptrCast array pointer to slice with complex length decrease" {
507507
try S.doTheTest(@splat(0));
508508
try comptime S.doTheTest(@splat(0));
509509
}
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+
}

0 commit comments

Comments
 (0)