| author | |
| committer | |
| log | 03ad862197d27fb079d16cabdf2026da23aa2653 |
| tree | 4a93dcada35e3bf50521efaa41679688cb16ab26 |
| parent | 66630f6c93da0d219d74026742c1cb5f64e858e8 |
| signature |
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 | } | ||
| 284 | 281 | ||
| 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..]; |
| 399 | 393 | ||
| 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..]; |
| 520 | 511 | ||
| 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)); |
| 682 | 682 | ||
| 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 | } |
| 689 | 689 | ||
| 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 | } |
| 706 | 718 | ||
| 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 | } |
| 715 | 731 |
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 | } |
| 6 | 6 | ||
| 7 | export 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 | // error | 7 | // error |
| 14 | // | 8 | // |
| 15 | // :4:5: error: found compile log statement | 9 | // :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) |