| author | |
| committer | |
| log | 1149e8bb088f48e29f3abc06196b1134f5e1c42f |
| tree | b3637be2086b25649d71e2d24d334aa634e87e03 |
| parent | 7d0b6956c0935807f0e5862c45da857e8e065c6b |
| parent | 480e7eec65c02952b71ecc2f4ff2adccb6092a5f |
| signature |
stage2: resolve panic on array-like tuple initialization8 files changed, 72 insertions(+), 13 deletions(-)
src/AstGen.zig+7-5| ... | @@ -4092,15 +4092,17 @@ fn structDeclInner( | ... | @@ -4092,15 +4092,17 @@ fn structDeclInner( |
| 4092 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); | 4092 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 4093 | wip_members.appendToField(doc_comment_index); | 4093 | wip_members.appendToField(doc_comment_index); |
| 4094 | 4094 | ||
| 4095 | known_non_opv = known_non_opv or | ||
| 4096 | nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); | ||
| 4097 | known_comptime_only = known_comptime_only or | ||
| 4098 | nodeImpliesComptimeOnly(tree, member.ast.type_expr); | ||
| 4099 | |||
| 4100 | const have_align = member.ast.align_expr != 0; | 4095 | const have_align = member.ast.align_expr != 0; |
| 4101 | const have_value = member.ast.value_expr != 0; | 4096 | const have_value = member.ast.value_expr != 0; |
| 4102 | const is_comptime = member.comptime_token != null; | 4097 | const is_comptime = member.comptime_token != null; |
| 4103 | const unused = false; | 4098 | const unused = false; |
| 4099 | |||
| 4100 | if (!is_comptime) { | ||
| 4101 | known_non_opv = known_non_opv or | ||
| 4102 | nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); | ||
| 4103 | known_comptime_only = known_comptime_only or | ||
| 4104 | nodeImpliesComptimeOnly(tree, member.ast.type_expr); | ||
| 4105 | } | ||
| 4104 | wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused }); | 4106 | wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused }); |
| 4105 | 4107 | ||
| 4106 | if (have_align) { | 4108 | if (have_align) { |
src/Sema.zig+8-5| ... | @@ -3203,11 +3203,6 @@ fn zirValidateArrayInit( | ... | @@ -3203,11 +3203,6 @@ fn zirValidateArrayInit( |
| 3203 | 3203 | ||
| 3204 | // Determine whether the value stored to this pointer is comptime-known. | 3204 | // Determine whether the value stored to this pointer is comptime-known. |
| 3205 | 3205 | ||
| 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 next | 3208 | // 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 | }; |
| 3225 | 3220 | ||
| 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 element | 3227 | // 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]) { |
| ... | @@ -20860,6 +20861,7 @@ pub fn typeHasOnePossibleValue( | ... | @@ -20860,6 +20861,7 @@ pub fn typeHasOnePossibleValue( |
| 20860 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); | 20861 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 20861 | const s = resolved_ty.castTag(.@"struct").?.data; | 20862 | const s = resolved_ty.castTag(.@"struct").?.data; |
| 20862 | for (s.fields.values()) |value| { | 20863 | for (s.fields.values()) |value| { |
| 20864 | if (value.is_comptime) continue; | ||
| 20863 | if ((try sema.typeHasOnePossibleValue(block, src, value.ty)) == null) { | 20865 | if ((try sema.typeHasOnePossibleValue(block, src, value.ty)) == null) { |
| 20864 | return null; | 20866 | return null; |
| 20865 | } | 20867 | } |
| ... | @@ -21532,6 +21534,7 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C | ... | @@ -21532,6 +21534,7 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 21532 | 21534 | ||
| 21533 | struct_obj.requires_comptime = .wip; | 21535 | struct_obj.requires_comptime = .wip; |
| 21534 | for (struct_obj.fields.values()) |field| { | 21536 | for (struct_obj.fields.values()) |field| { |
| 21537 | if (field.is_comptime) continue; | ||
| 21535 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | 21538 | if (try sema.typeRequiresComptime(block, src, field.ty)) { |
| 21536 | struct_obj.requires_comptime = .yes; | 21539 | struct_obj.requires_comptime = .yes; |
| 21537 | return true; | 21540 | return true; |
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; | ||
| 5425 | 5427 | ||
| 5426 | // TODO Sema should emit a different instruction when the store should | 5428 | // 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 undefined | 5443 | // TODO generate valgrind client request to mark byte range as undefined |
src/type.zig+1| ... | @@ -2098,6 +2098,7 @@ pub const Type = extern union { | ... | @@ -2098,6 +2098,7 @@ pub const Type = extern union { |
| 2098 | } | 2098 | } |
| 2099 | assert(struct_obj.haveFieldTypes()); | 2099 | assert(struct_obj.haveFieldTypes()); |
| 2100 | for (struct_obj.fields.values()) |value| { | 2100 | for (struct_obj.fields.values()) |value| { |
| 2101 | if (value.is_comptime) continue; | ||
| 2101 | if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) | 2102 | if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) |
| 2102 | return true; | 2103 | return true; |
| 2103 | } else { | 2104 | } else { |
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 @@ | ||
| 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 == .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 @@ | ||
| 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 | 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 @@ | ||
| 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 | } | ||