authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-04-16 21:49:08+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-04-17 13:41:25+01:00
log03ad862197d27fb079d16cabdf2026da23aa2653
tree4a93dcada35e3bf50521efaa41679688cb16ab26
parent66630f6c93da0d219d74026742c1cb5f64e858e8
signaturelock-open Commit is signed but in an unrecognized format.

compiler: un-implement #19634

This commit reverts the handling of partially-undefined values in bitcasting to transform these bits into an arbitrary numeric value, like happens on `master` today. As @andrewrk rightly points out, #19634 has unfortunate consequences for the standard library, and likely requires more thought. To avoid a major breaking change, it has been decided to revert this design decision for now, and make a more informed decision further down the line.

4 files changed, 21 insertions(+), 30 deletions(-)

lib/std/net.zig-9
...@@ -278,9 +278,6 @@ pub const Ip4Address = extern struct {...@@ -278,9 +278,6 @@ pub const Ip4Address = extern struct {
278 },278 },
279 };279 };
280 const out_ptr = mem.asBytes(&result.sa.addr);280 const out_ptr = mem.asBytes(&result.sa.addr);
281 if (@inComptime()) {
282 @memset(out_ptr, 0); // TODO: #19634
283 }
284281
285 var x: u8 = 0;282 var x: u8 = 0;
286 var index: u8 = 0;283 var index: u8 = 0;
...@@ -392,9 +389,6 @@ pub const Ip6Address = extern struct {...@@ -392,9 +389,6 @@ pub const Ip6Address = extern struct {
392 .addr = undefined,389 .addr = undefined,
393 },390 },
394 };391 };
395 if (@inComptime()) {
396 @memset(std.mem.asBytes(&result.sa.addr), 0); // TODO: #19634
397 }
398 var ip_slice: *[16]u8 = result.sa.addr[0..];392 var ip_slice: *[16]u8 = result.sa.addr[0..];
399393
400 var tail: [16]u8 = undefined;394 var tail: [16]u8 = undefined;
...@@ -513,9 +507,6 @@ pub const Ip6Address = extern struct {...@@ -513,9 +507,6 @@ pub const Ip6Address = extern struct {
513 .addr = undefined,507 .addr = undefined,
514 },508 },
515 };509 };
516 if (@inComptime()) {
517 @memset(std.mem.asBytes(&result.sa.addr), 0); // TODO: #19634
518 }
519 var ip_slice: *[16]u8 = result.sa.addr[0..];510 var ip_slice: *[16]u8 = result.sa.addr[0..];
520511
521 var tail: [16]u8 = undefined;512 var tail: [16]u8 = undefined;
lib/std/packed_int_array.zig-8
...@@ -214,10 +214,6 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim...@@ -214,10 +214,6 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
214 /// or, more likely, an array literal.214 /// or, more likely, an array literal.
215 pub fn init(ints: [int_count]Int) Self {215 pub fn init(ints: [int_count]Int) Self {
216 var self: Self = undefined;216 var self: Self = undefined;
217 if (@inComptime()) {
218 // TODO: #19634
219 @memset(&self.bytes, 0xAA);
220 }
221 for (ints, 0..) |int, i| self.set(i, int);217 for (ints, 0..) |int, i| self.set(i, int);
222 return self;218 return self;
223 }219 }
...@@ -225,10 +221,6 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim...@@ -225,10 +221,6 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
225 /// Initialize all entries of a packed array to the same value.221 /// Initialize all entries of a packed array to the same value.
226 pub fn initAllTo(int: Int) Self {222 pub fn initAllTo(int: Int) Self {
227 var self: Self = undefined;223 var self: Self = undefined;
228 if (@inComptime()) {
229 // TODO: #19634
230 @memset(&self.bytes, 0xAA);
231 }
232 self.setAll(int);224 self.setAll(int);
233 return self;225 return self;
234 }226 }
src/Sema/bitcast.zig+21-5
...@@ -681,12 +681,24 @@ const PackValueBits = struct {...@@ -681,12 +681,24 @@ const PackValueBits = struct {
681 const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));681 const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));
682682
683 for (vals) |val| {683 for (vals) |val| {
684 if (Value.fromInterned(val).isUndef(zcu)) {684 if (!Value.fromInterned(val).isUndef(zcu)) break;
685 // The value contains undef bits, so is considered entirely undef.685 } else {
686 return zcu.undefValue(want_ty);686 // All bits of the value are `undefined`.
687 }687 return zcu.undefValue(want_ty);
688 }688 }
689689
690 // TODO: we need to decide how to handle partially-undef values here.
691 // Currently, a value with some undefined bits becomes `0xAA` so that we
692 // preserve the well-defined bits, because we can't currently represent
693 // a partially-undefined primitive (e.g. an int with some undef bits).
694 // In future, we probably want to take one of these two routes:
695 // * Define that if any bits are `undefined`, the entire value is `undefined`.
696 // This is a major breaking change, and probably a footgun.
697 // * Introduce tracking for partially-undef values at comptime.
698 // This would complicate a lot of operations in Sema, such as basic
699 // arithmetic.
700 // This design complexity is tracked by #19634.
701
690 ptr_cast: {702 ptr_cast: {
691 if (vals.len != 1) break :ptr_cast;703 if (vals.len != 1) break :ptr_cast;
692 const val = Value.fromInterned(vals[0]);704 const val = Value.fromInterned(vals[0]);
...@@ -705,11 +717,15 @@ const PackValueBits = struct {...@@ -705,11 +717,15 @@ const PackValueBits = struct {
705 }717 }
706718
707 const buf = try pack.arena.alloc(u8, @intCast((buf_bits + 7) / 8));719 const buf = try pack.arena.alloc(u8, @intCast((buf_bits + 7) / 8));
720 // We will skip writing undefined values, so mark the buffer as `0xAA` so we get "undefined" bits.
721 @memset(buf, 0xAA);
708 var cur_bit_off: usize = 0;722 var cur_bit_off: usize = 0;
709 for (vals) |ip_val| {723 for (vals) |ip_val| {
710 const val = Value.fromInterned(ip_val);724 const val = Value.fromInterned(ip_val);
711 const ty = val.typeOf(zcu);725 const ty = val.typeOf(zcu);
712 try val.writeToPackedMemory(ty, zcu, buf, cur_bit_off);726 if (!val.isUndef(zcu)) {
727 try val.writeToPackedMemory(ty, zcu, buf, cur_bit_off);
728 }
713 cur_bit_off += @intCast(ty.bitSize(zcu));729 cur_bit_off += @intCast(ty.bitSize(zcu));
714 }730 }
715731
test/cases/compile_errors/bitcast_undef.zig-8
...@@ -4,17 +4,9 @@ export fn entry1() void {...@@ -4,17 +4,9 @@ export fn entry1() void {
4 @compileLog(y);4 @compileLog(y);
5}5}
66
7export fn entry2() void {
8 const x: packed struct { x: u16, y: u16 } = .{ .x = 123, .y = undefined };
9 const y: u32 = @bitCast(x);
10 @compileLog(y);
11}
12
13// error7// error
14//8//
15// :4:5: error: found compile log statement9// :4:5: error: found compile log statement
16// :10:5: note: also here
17//10//
18// Compile Log Output:11// Compile Log Output:
19// @as(u32, undefined)12// @as(u32, undefined)
20// @as(u32, undefined)