Skip to content

Commit c50d36f

Browse files
committed
stage2: Fix panic on initializing comptime fields in tuple
This resolves ziglang#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.
1 parent 7cafa7a commit c50d36f

File tree

6 files changed

+60
-8
lines changed

6 files changed

+60
-8
lines changed

src/Sema.zig

+6-5
Original file line numberDiff line numberDiff line change
@@ -3198,11 +3198,6 @@ fn zirValidateArrayInit(
31983198

31993199
// Determine whether the value stored to this pointer is comptime-known.
32003200

3201-
if (opt_opv) |opv| {
3202-
element_vals[i] = opv;
3203-
continue;
3204-
}
3205-
32063201
const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
32073202
const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
32083203
// Find the block index of the elem_ptr so that we can look at the next
@@ -3218,6 +3213,12 @@ fn zirValidateArrayInit(
32183213
break :inst block.instructions.items[block_index + 1];
32193214
};
32203215

3216+
// Array has one possible value, so value is always comptime-known
3217+
if (opt_opv) |opv| {
3218+
element_vals[i] = opv;
3219+
continue;
3220+
}
3221+
32213222
// If the next instructon is a store with a comptime operand, this element
32223223
// is comptime.
32233224
switch (air_tags[next_air_inst]) {

src/codegen/llvm.zig

+4-3
Original file line numberDiff line numberDiff line change
@@ -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
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ test {
6363
_ = @import("behavior/bugs/10970.zig");
6464
_ = @import("behavior/bugs/11046.zig");
6565
_ = @import("behavior/bugs/11139.zig");
66+
_ = @import("behavior/bugs/11159.zig");
67+
_ = @import("behavior/bugs/11162.zig");
6668
_ = @import("behavior/bugs/11165.zig");
69+
_ = @import("behavior/bugs/11182.zig");
6770
_ = @import("behavior/call.zig");
6871
_ = @import("behavior/cast.zig");
6972
_ = @import("behavior/comptime_memory.zig");

test/behavior/bugs/11159.zig

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const std = @import("std");
2+
const builtin = @import("builtin");
3+
4+
test {
5+
const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
6+
var a: T = .{ 0, 0 };
7+
_ = a;
8+
}
9+
10+
test {
11+
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
12+
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13+
14+
const S = struct {
15+
comptime x: i32 = 0,
16+
comptime y: u32 = 0,
17+
};
18+
var a: S = .{};
19+
_ = a;
20+
var b = S{};
21+
_ = b;
22+
}

test/behavior/bugs/11162.zig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const std = @import("std");
2+
const builtin = @import("builtin");
3+
const expect = std.testing.expect;
4+
5+
test {
6+
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
7+
8+
var x: u32 = 15;
9+
const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
10+
var a: T = .{ -1234, 5678, x + 1 };
11+
12+
try expect(a[0] == -1234);
13+
try expect(a[1] == 5678);
14+
try expect(a[2] == 16);
15+
}

test/behavior/bugs/11182.zig

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const std = @import("std");
2+
const builtin = @import("builtin");
3+
4+
test {
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+
}

0 commit comments

Comments
 (0)