authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-03-15 14:00:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-15 17:01:16-07:00
log480e7eec65c02952b71ecc2f4ff2adccb6092a5f
treeb3637be2086b25649d71e2d24d334aa634e87e03
parent762c4a876bfa999d5f49edc7bbaf2917c06d320d

stage2: Fix panic on initializing comptime fields in tuple

This resolves https://github.com/ziglang/zig/issues/11159 The problem was that: 1. We were not correctly deleting the field stores after recognizing that an array initializer was a comptime-known value. 2. LLVM was not checking that the final type had no runtime bits, and so would generate an invalid store. This also adds several test cases for related bugs, just to check these in for later work.

6 files changed, 62 insertions(+), 8 deletions(-)

src/Sema.zig+6-5
......@@ -3203,11 +3203,6 @@ fn zirValidateArrayInit(
32033203
32043204 // Determine whether the value stored to this pointer is comptime-known.
32053205
3206 if (opt_opv) |opv| {
3207 element_vals[i] = opv;
3208 continue;
3209 }
3210
32113206 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
32123207 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
32133208 // Find the block index of the elem_ptr so that we can look at the next
......@@ -3223,6 +3218,12 @@ fn zirValidateArrayInit(
32233218 break :inst block.instructions.items[block_index + 1];
32243219 };
32253220
3221 // Array has one possible value, so value is always comptime-known
3222 if (opt_opv) |opv| {
3223 element_vals[i] = opv;
3224 continue;
3225 }
3226
32263227 // If the next instructon is a store with a comptime operand, this element
32273228 // is comptime.
32283229 switch (air_tags[next_air_inst]) {
src/codegen/llvm.zig+4-3
......@@ -5422,21 +5422,22 @@ pub const FuncGen = struct {
54225422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
54235423 const dest_ptr = try self.resolveInst(bin_op.lhs);
54245424 const ptr_ty = self.air.typeOf(bin_op.lhs);
5425 const operand_ty = ptr_ty.childType();
5426 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
54255427
54265428 // TODO Sema should emit a different instruction when the store should
54275429 // possibly do the safety 0xaa bytes for undefined.
54285430 const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
54295431 if (val_is_undef) {
5430 const elem_ty = ptr_ty.childType();
54315432 const target = self.dg.module.getTarget();
5432 const elem_size = elem_ty.abiSize(target);
5433 const operand_size = operand_ty.abiSize(target);
54335434 const u8_llvm_ty = self.context.intType(8);
54345435 const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
54355436 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
54365437 const fill_char = u8_llvm_ty.constInt(0xaa, .False);
54375438 const dest_ptr_align = ptr_ty.ptrAlignment(target);
54385439 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
5439 const len = usize_llvm_ty.constInt(elem_size, .False);
5440 const len = usize_llvm_ty.constInt(operand_size, .False);
54405441 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
54415442 if (self.dg.module.comp.bin_file.options.valgrind) {
54425443 // TODO generate valgrind client request to mark byte range as undefined
test/behavior.zig+3
......@@ -65,8 +65,11 @@ test {
6565 _ = @import("behavior/bugs/10970.zig");
6666 _ = @import("behavior/bugs/11046.zig");
6767 _ = @import("behavior/bugs/11139.zig");
68 _ = @import("behavior/bugs/11159.zig");
69 _ = @import("behavior/bugs/11162.zig");
6870 _ = @import("behavior/bugs/11165.zig");
6971 _ = @import("behavior/bugs/11181.zig");
72 _ = @import("behavior/bugs/11182.zig");
7073 _ = @import("behavior/call.zig");
7174 _ = @import("behavior/cast.zig");
7275 _ = @import("behavior/comptime_memory.zig");
test/behavior/bugs/11159.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4test {
5 const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
6 var a: T = .{ 0, 0 };
7 _ = a;
8}
9
10test {
11 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14
15 const S = struct {
16 comptime x: i32 = 0,
17 comptime y: u32 = 0,
18 };
19 var a: S = .{};
20 _ = a;
21 var b = S{};
22 _ = b;
23}
test/behavior/bugs/11162.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5test {
6 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
8
9 var x: u32 = 15;
10 const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
11 var a: T = .{ -1234, 5678, x + 1 };
12
13 try expect(a[0] == -1234);
14 try expect(a[1] == 5678);
15 try expect(a[2] == 16);
16}
test/behavior/bugs/11182.zig created+10
......@@ -0,0 +1,10 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4test {
5 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
6
7 const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
8 var a = T{ 0, 0 };
9 _ = a;
10}