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(...@@ -3203,11 +3203,6 @@ fn zirValidateArrayInit(
32033203
3204 // Determine whether the value stored to this pointer is comptime-known.3204 // 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
3211 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;3206 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
3212 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;3207 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
3213 // Find the block index of the elem_ptr so that we can look at the next3208 // Find the block index of the elem_ptr so that we can look at the next
...@@ -3223,6 +3218,12 @@ fn zirValidateArrayInit(...@@ -3223,6 +3218,12 @@ fn zirValidateArrayInit(
3223 break :inst block.instructions.items[block_index + 1];3218 break :inst block.instructions.items[block_index + 1];
3224 };3219 };
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
3226 // If the next instructon is a store with a comptime operand, this element3227 // If the next instructon is a store with a comptime operand, this element
3227 // is comptime.3228 // is comptime.
3228 switch (air_tags[next_air_inst]) {3229 switch (air_tags[next_air_inst]) {
src/codegen/llvm.zig+4-3
...@@ -5422,21 +5422,22 @@ pub const FuncGen = struct {...@@ -5422,21 +5422,22 @@ pub const FuncGen = struct {
5422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5423 const dest_ptr = try self.resolveInst(bin_op.lhs);5423 const dest_ptr = try self.resolveInst(bin_op.lhs);
5424 const ptr_ty = self.air.typeOf(bin_op.lhs);5424 const ptr_ty = self.air.typeOf(bin_op.lhs);
5425 const operand_ty = ptr_ty.childType();
5426 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
54255427
5426 // TODO Sema should emit a different instruction when the store should5428 // TODO Sema should emit a different instruction when the store should
5427 // possibly do the safety 0xaa bytes for undefined.5429 // possibly do the safety 0xaa bytes for undefined.
5428 const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;5430 const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
5429 if (val_is_undef) {5431 if (val_is_undef) {
5430 const elem_ty = ptr_ty.childType();
5431 const target = self.dg.module.getTarget();5432 const target = self.dg.module.getTarget();
5432 const elem_size = elem_ty.abiSize(target);5433 const operand_size = operand_ty.abiSize(target);
5433 const u8_llvm_ty = self.context.intType(8);5434 const u8_llvm_ty = self.context.intType(8);
5434 const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);5435 const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
5435 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");5436 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
5436 const fill_char = u8_llvm_ty.constInt(0xaa, .False);5437 const fill_char = u8_llvm_ty.constInt(0xaa, .False);
5437 const dest_ptr_align = ptr_ty.ptrAlignment(target);5438 const dest_ptr_align = ptr_ty.ptrAlignment(target);
5438 const usize_llvm_ty = try self.dg.llvmType(Type.usize);5439 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);
5440 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());5441 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
5441 if (self.dg.module.comp.bin_file.options.valgrind) {5442 if (self.dg.module.comp.bin_file.options.valgrind) {
5442 // TODO generate valgrind client request to mark byte range as undefined5443 // TODO generate valgrind client request to mark byte range as undefined
test/behavior.zig+3
...@@ -65,8 +65,11 @@ test {...@@ -65,8 +65,11 @@ test {
65 _ = @import("behavior/bugs/10970.zig");65 _ = @import("behavior/bugs/10970.zig");
66 _ = @import("behavior/bugs/11046.zig");66 _ = @import("behavior/bugs/11046.zig");
67 _ = @import("behavior/bugs/11139.zig");67 _ = @import("behavior/bugs/11139.zig");
68 _ = @import("behavior/bugs/11159.zig");
69 _ = @import("behavior/bugs/11162.zig");
68 _ = @import("behavior/bugs/11165.zig");70 _ = @import("behavior/bugs/11165.zig");
69 _ = @import("behavior/bugs/11181.zig");71 _ = @import("behavior/bugs/11181.zig");
72 _ = @import("behavior/bugs/11182.zig");
70 _ = @import("behavior/call.zig");73 _ = @import("behavior/call.zig");
71 _ = @import("behavior/cast.zig");74 _ = @import("behavior/cast.zig");
72 _ = @import("behavior/comptime_memory.zig");75 _ = @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}