Merge pull request #11185 from topolarity/bugfix-11159

stage2: resolve panic on array-like tuple initialization
This commit is contained in:
Andrew Kelley 2022-03-15 20:03:58 -04:00 committed by GitHub
commit 1149e8bb08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 13 deletions

View File

@ -4092,15 +4092,17 @@ fn structDeclInner(
const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
wip_members.appendToField(doc_comment_index);
known_non_opv = known_non_opv or
nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
known_comptime_only = known_comptime_only or
nodeImpliesComptimeOnly(tree, member.ast.type_expr);
const have_align = member.ast.align_expr != 0;
const have_value = member.ast.value_expr != 0;
const is_comptime = member.comptime_token != null;
const unused = false;
if (!is_comptime) {
known_non_opv = known_non_opv or
nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
known_comptime_only = known_comptime_only or
nodeImpliesComptimeOnly(tree, member.ast.type_expr);
}
wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused });
if (have_align) {

View File

@ -3203,11 +3203,6 @@ fn zirValidateArrayInit(
// Determine whether the value stored to this pointer is comptime-known.
if (opt_opv) |opv| {
element_vals[i] = opv;
continue;
}
const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
// Find the block index of the elem_ptr so that we can look at the next
@ -3223,6 +3218,12 @@ fn zirValidateArrayInit(
break :inst block.instructions.items[block_index + 1];
};
// Array has one possible value, so value is always comptime-known
if (opt_opv) |opv| {
element_vals[i] = opv;
continue;
}
// If the next instructon is a store with a comptime operand, this element
// is comptime.
switch (air_tags[next_air_inst]) {
@ -20860,6 +20861,7 @@ pub fn typeHasOnePossibleValue(
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const s = resolved_ty.castTag(.@"struct").?.data;
for (s.fields.values()) |value| {
if (value.is_comptime) continue;
if ((try sema.typeHasOnePossibleValue(block, src, value.ty)) == null) {
return null;
}
@ -21532,6 +21534,7 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
struct_obj.requires_comptime = .wip;
for (struct_obj.fields.values()) |field| {
if (field.is_comptime) continue;
if (try sema.typeRequiresComptime(block, src, field.ty)) {
struct_obj.requires_comptime = .yes;
return true;

View File

@ -5422,21 +5422,22 @@ pub const FuncGen = struct {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const dest_ptr = try self.resolveInst(bin_op.lhs);
const ptr_ty = self.air.typeOf(bin_op.lhs);
const operand_ty = ptr_ty.childType();
if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
// TODO Sema should emit a different instruction when the store should
// possibly do the safety 0xaa bytes for undefined.
const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
if (val_is_undef) {
const elem_ty = ptr_ty.childType();
const target = self.dg.module.getTarget();
const elem_size = elem_ty.abiSize(target);
const operand_size = operand_ty.abiSize(target);
const u8_llvm_ty = self.context.intType(8);
const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
const fill_char = u8_llvm_ty.constInt(0xaa, .False);
const dest_ptr_align = ptr_ty.ptrAlignment(target);
const usize_llvm_ty = try self.dg.llvmType(Type.usize);
const len = usize_llvm_ty.constInt(elem_size, .False);
const len = usize_llvm_ty.constInt(operand_size, .False);
_ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
if (self.dg.module.comp.bin_file.options.valgrind) {
// TODO generate valgrind client request to mark byte range as undefined

View File

@ -2098,6 +2098,7 @@ pub const Type = extern union {
}
assert(struct_obj.haveFieldTypes());
for (struct_obj.fields.values()) |value| {
if (value.is_comptime) continue;
if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
return true;
} else {

View File

@ -65,8 +65,11 @@ test {
_ = @import("behavior/bugs/10970.zig");
_ = @import("behavior/bugs/11046.zig");
_ = @import("behavior/bugs/11139.zig");
_ = @import("behavior/bugs/11159.zig");
_ = @import("behavior/bugs/11162.zig");
_ = @import("behavior/bugs/11165.zig");
_ = @import("behavior/bugs/11181.zig");
_ = @import("behavior/bugs/11182.zig");
_ = @import("behavior/call.zig");
_ = @import("behavior/cast.zig");
_ = @import("behavior/comptime_memory.zig");

View File

@ -0,0 +1,23 @@
const std = @import("std");
const builtin = @import("builtin");
test {
const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
var a: T = .{ 0, 0 };
_ = a;
}
test {
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
const S = struct {
comptime x: i32 = 0,
comptime y: u32 = 0,
};
var a: S = .{};
_ = a;
var b = S{};
_ = b;
}

View File

@ -0,0 +1,16 @@
const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
test {
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
var x: u32 = 15;
const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
var a: T = .{ -1234, 5678, x + 1 };
try expect(a[0] == -1234);
try expect(a[1] == 5678);
try expect(a[2] == 16);
}

View File

@ -0,0 +1,10 @@
const std = @import("std");
const builtin = @import("builtin");
test {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
var a = T{ 0, 0 };
_ = a;
}