false positive `@bitCast size mismatch` compile error when using sentineled array
Zig Version
0.11.0-dev.1199+1878bdfbb
Steps to Reproduce and Observed Behavior
const std = @import("std");
const expect = std.testing.expect;
test "@bitCast size with sentineled array" {
const x = @bitCast(u64, "Location".*);
const y = std.mem.readIntNative(u64, "Location");
try expect(x == y);
}
test3.zig:5:39: error: @bitCast size mismatch: destination type 'u64' has 64 bits but source type '[8:0]u8' has 72 bits
const x = @bitCast(u64, "Location".*);
~~~~~~~~~~^~
Expected Behavior
Test passed.
Is the sentinel always ignored or would @bitCast(u64, "Locatio".*) also work?
Hmmm. I think the sentinel would be ignored, making your example a compile error. To not ignore it, one would do this:
const std = @import("std");
const expect = std.testing.expect;
test "@bitCast size with sentineled array, including sentinel" {
const x = @bitCast(u64, "Locatio"[0..8].*);
const y = std.mem.readIntNative(u64, "Locatio\x00");
try expect(x == y);
}
$ stage4/bin/zig test test3.zig
Test [1/1] test.@bitCast size with sentineled array... FAIL (TestUnexpectedResult)
/home/andy/dev/zig/lib/std/testing.zig:509:14: 0x20bec7 in expect (test)
if (!ok) return error.TestUnexpectedResult;
^
/home/andy/dev/zig/build-release/test3.zig:7:5: 0x20c036 in test.@bitCast size with sentineled array (test)
try expect(x == y);
^
0 passed; 0 skipped; 1 failed.
I would expect this test to pass as well.
That seems good enough. One downside to this is that it introduces an inconsistency to @bitCast:
// in @bitCast(A, @as(B, b))
if (B == sentineled array)
assert(@sizeOf(A) == @sizeOf(B) - @sizeOf(B.Elem))
else
assert(@sizeOf(A) == @sizeOf(B));
I want to update @bitCast to semantically operate at a "bit-level". Instead of being defined in terms of @ptrCast, I think @bitCast should be defined something like this:
- in an abstract sense, explode out the value into its bits. for example, a u32 has lsb to msb which are independent of endianness.
- reinterpret those bits using a different type
- reconstruct those bits into the new type
This has a couple of nice properties:
- bitcasting between floats and integers works independently of endianness, which is a property I believe we already rely on.
- bitcasting between, for example, f80 and u80 would work as one expects, even when f80 is represented on the target as a 128-bit struct with padding.
cc @SpexGuy I think we discussed this a long time ago but did not reach a conclusion, or perhaps I have reverted to a pre-discussion understanding of the situation.