commit 1149e8bb088f48e29f3abc06196b1134f5e1c42f (tree)
parent 7d0b6956c0935807f0e5862c45da857e8e065c6b
Author: Andrew Kelley <andrew@ziglang.org>
Date: Tue, 15 Mar 2022 20:03:58 -0400
Merge pull request #11185 from topolarity/bugfix-11159
stage2: resolve panic on array-like tuple initialization
Diffstat:
8 files changed, 72 insertions(+), 13 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
@@ -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) {
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -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;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -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
diff --git a/src/type.zig b/src/type.zig
@@ -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 {
diff --git a/test/behavior.zig b/test/behavior.zig
@@ -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");
diff --git a/test/behavior/bugs/11159.zig b/test/behavior/bugs/11159.zig
@@ -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;
+}
diff --git a/test/behavior/bugs/11162.zig b/test/behavior/bugs/11162.zig
@@ -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);
+}
diff --git a/test/behavior/bugs/11182.zig b/test/behavior/bugs/11182.zig
@@ -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;
+}