| ... | ... | @@ -3772,6 +3772,7 @@ fn validateStructInit( |
| 3772 | 3772 | } |
| 3773 | 3773 | |
| 3774 | 3774 | var root_msg: ?*Module.ErrorMsg = null; |
| 3775 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 3775 | 3776 | |
| 3776 | 3777 | const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); |
| 3777 | 3778 | if ((is_comptime or block.is_comptime) and |
| ... | ... | @@ -3947,6 +3948,7 @@ fn validateStructInit( |
| 3947 | 3948 | } |
| 3948 | 3949 | |
| 3949 | 3950 | if (root_msg) |msg| { |
| 3951 | root_msg = null; |
| 3950 | 3952 | if (struct_ty.castTag(.@"struct")) |struct_obj| { |
| 3951 | 3953 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); |
| 3952 | 3954 | defer gpa.free(fqn); |
| ... | ... | @@ -4005,6 +4007,8 @@ fn zirValidateArrayInit( |
| 4005 | 4007 | if (instrs.len != array_len and array_ty.isTuple()) { |
| 4006 | 4008 | const struct_obj = array_ty.castTag(.tuple).?.data; |
| 4007 | 4009 | var root_msg: ?*Module.ErrorMsg = null; |
| 4010 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 4011 | |
| 4008 | 4012 | for (struct_obj.values) |default_val, i| { |
| 4009 | 4013 | if (i < instrs.len) continue; |
| 4010 | 4014 | |
| ... | ... | @@ -4019,6 +4023,7 @@ fn zirValidateArrayInit( |
| 4019 | 4023 | } |
| 4020 | 4024 | |
| 4021 | 4025 | if (root_msg) |msg| { |
| 4026 | root_msg = null; |
| 4022 | 4027 | return sema.failWithOwnedErrorMsg(msg); |
| 4023 | 4028 | } |
| 4024 | 4029 | } |
| ... | ... | @@ -8964,12 +8969,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8964 | 8969 | }, |
| 8965 | 8970 | }; |
| 8966 | 8971 | |
| 8967 | | const union_originally = blk: { |
| 8972 | const maybe_union_ty = blk: { |
| 8968 | 8973 | const zir_data = sema.code.instructions.items(.data); |
| 8969 | 8974 | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 8970 | 8975 | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 8971 | | break :blk sema.typeOf(raw_operand).zigTypeTag() == .Union; |
| 8976 | break :blk sema.typeOf(raw_operand); |
| 8972 | 8977 | }; |
| 8978 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; |
| 8979 | var seen_union_fields: []?Module.SwitchProngSrc = &.{}; |
| 8980 | defer gpa.free(seen_union_fields); |
| 8973 | 8981 | |
| 8974 | 8982 | const operand_ty = sema.typeOf(operand); |
| 8975 | 8983 | |
| ... | ... | @@ -9004,7 +9012,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9004 | 9012 | .Union => unreachable, // handled in zirSwitchCond |
| 9005 | 9013 | .Enum => { |
| 9006 | 9014 | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9007 | | defer gpa.free(seen_fields); |
| 9015 | defer if (!union_originally) gpa.free(seen_fields); |
| 9016 | if (union_originally) seen_union_fields = seen_fields; |
| 9008 | 9017 | mem.set(?Module.SwitchProngSrc, seen_fields, null); |
| 9009 | 9018 | |
| 9010 | 9019 | // This is used for non-exhaustive enum values that do not correspond to any tags. |
| ... | ... | @@ -9637,18 +9646,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9637 | 9646 | const item = try sema.resolveInst(item_ref); |
| 9638 | 9647 | // `item` is already guaranteed to be constant known. |
| 9639 | 9648 | |
| 9640 | | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9641 | | error.ComptimeBreak => { |
| 9642 | | const zir_datas = sema.code.instructions.items(.data); |
| 9643 | | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9644 | | try sema.addRuntimeBreak(&case_block, .{ |
| 9645 | | .block_inst = break_data.block_inst, |
| 9646 | | .operand = break_data.operand, |
| 9647 | | .inst = sema.comptime_break_inst, |
| 9648 | | }); |
| 9649 | | }, |
| 9650 | | else => |e| return e, |
| 9651 | | }; |
| 9649 | const analyze_body = if (union_originally) blk: { |
| 9650 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 9651 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 9652 | break :blk field_ty.zigTypeTag() != .NoReturn; |
| 9653 | } else true; |
| 9654 | |
| 9655 | if (analyze_body) { |
| 9656 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9657 | error.ComptimeBreak => { |
| 9658 | const zir_datas = sema.code.instructions.items(.data); |
| 9659 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9660 | try sema.addRuntimeBreak(&case_block, .{ |
| 9661 | .block_inst = break_data.block_inst, |
| 9662 | .operand = break_data.operand, |
| 9663 | .inst = sema.comptime_break_inst, |
| 9664 | }); |
| 9665 | }, |
| 9666 | else => |e| return e, |
| 9667 | }; |
| 9668 | } else { |
| 9669 | _ = try case_block.addNoOp(.unreach); |
| 9670 | } |
| 9652 | 9671 | |
| 9653 | 9672 | try wip_captures.finalize(); |
| 9654 | 9673 | |
| ... | ... | @@ -9689,20 +9708,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9689 | 9708 | if (ranges_len == 0) { |
| 9690 | 9709 | cases_len += 1; |
| 9691 | 9710 | |
| 9711 | const analyze_body = if (union_originally) |
| 9712 | for (items) |item_ref| { |
| 9713 | const item = try sema.resolveInst(item_ref); |
| 9714 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 9715 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 9716 | if (field_ty.zigTypeTag() != .NoReturn) break true; |
| 9717 | } else false |
| 9718 | else |
| 9719 | true; |
| 9720 | |
| 9692 | 9721 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 9693 | 9722 | extra_index += body_len; |
| 9694 | | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9695 | | error.ComptimeBreak => { |
| 9696 | | const zir_datas = sema.code.instructions.items(.data); |
| 9697 | | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9698 | | try sema.addRuntimeBreak(&case_block, .{ |
| 9699 | | .block_inst = break_data.block_inst, |
| 9700 | | .operand = break_data.operand, |
| 9701 | | .inst = sema.comptime_break_inst, |
| 9702 | | }); |
| 9703 | | }, |
| 9704 | | else => |e| return e, |
| 9705 | | }; |
| 9723 | if (analyze_body) { |
| 9724 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 9725 | error.ComptimeBreak => { |
| 9726 | const zir_datas = sema.code.instructions.items(.data); |
| 9727 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 9728 | try sema.addRuntimeBreak(&case_block, .{ |
| 9729 | .block_inst = break_data.block_inst, |
| 9730 | .operand = break_data.operand, |
| 9731 | .inst = sema.comptime_break_inst, |
| 9732 | }); |
| 9733 | }, |
| 9734 | else => |e| return e, |
| 9735 | }; |
| 9736 | } else { |
| 9737 | _ = try case_block.addNoOp(.unreach); |
| 9738 | } |
| 9706 | 9739 | |
| 9707 | 9740 | try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + |
| 9708 | 9741 | case_block.instructions.items.len); |
| ... | ... | @@ -9824,7 +9857,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9824 | 9857 | case_block.instructions.shrinkRetainingCapacity(0); |
| 9825 | 9858 | case_block.wip_capture_scope = wip_captures.scope; |
| 9826 | 9859 | |
| 9827 | | if (special.body.len != 0) { |
| 9860 | const analyze_body = if (union_originally) |
| 9861 | for (seen_union_fields) |seen_field, index| { |
| 9862 | if (seen_field != null) continue; |
| 9863 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; |
| 9864 | const field_ty = union_obj.fields.values()[index].ty; |
| 9865 | if (field_ty.zigTypeTag() != .NoReturn) break true; |
| 9866 | } else false |
| 9867 | else |
| 9868 | true; |
| 9869 | |
| 9870 | if (special.body.len != 0 and analyze_body) { |
| 9828 | 9871 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 9829 | 9872 | error.ComptimeBreak => { |
| 9830 | 9873 | const zir_datas = sema.code.instructions.items(.data); |
| ... | ... | @@ -13225,6 +13268,14 @@ fn analyzeCmpUnionTag( |
| 13225 | 13268 | const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src); |
| 13226 | 13269 | const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); |
| 13227 | 13270 | |
| 13271 | if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| { |
| 13272 | if (enum_val.isUndef()) return sema.addConstUndef(Type.bool); |
| 13273 | const field_ty = union_ty.unionFieldType(enum_val, sema.mod); |
| 13274 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 13275 | return Air.Inst.Ref.bool_false; |
| 13276 | } |
| 13277 | } |
| 13278 | |
| 13228 | 13279 | return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src); |
| 13229 | 13280 | } |
| 13230 | 13281 | |
| ... | ... | @@ -15579,6 +15630,8 @@ fn finishStructInit( |
| 15579 | 15630 | const gpa = sema.gpa; |
| 15580 | 15631 | |
| 15581 | 15632 | var root_msg: ?*Module.ErrorMsg = null; |
| 15633 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 15634 | |
| 15582 | 15635 | if (struct_ty.isAnonStruct()) { |
| 15583 | 15636 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; |
| 15584 | 15637 | for (struct_obj.values) |default_val, i| { |
| ... | ... | @@ -15634,6 +15687,7 @@ fn finishStructInit( |
| 15634 | 15687 | } |
| 15635 | 15688 | |
| 15636 | 15689 | if (root_msg) |msg| { |
| 15690 | root_msg = null; |
| 15637 | 15691 | if (struct_ty.castTag(.@"struct")) |struct_obj| { |
| 15638 | 15692 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); |
| 15639 | 15693 | defer gpa.free(fqn); |
| ... | ... | @@ -21682,6 +21736,18 @@ fn unionFieldPtr( |
| 21682 | 21736 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 21683 | 21737 | }); |
| 21684 | 21738 | |
| 21739 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { |
| 21740 | const msg = msg: { |
| 21741 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); |
| 21742 | errdefer msg.destroy(sema.gpa); |
| 21743 | |
| 21744 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); |
| 21745 | try sema.addDeclaredHereNote(msg, union_ty); |
| 21746 | break :msg msg; |
| 21747 | }; |
| 21748 | return sema.failWithOwnedErrorMsg(msg); |
| 21749 | } |
| 21750 | |
| 21685 | 21751 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { |
| 21686 | 21752 | switch (union_obj.layout) { |
| 21687 | 21753 | .Auto => if (!initializing) { |
| ... | ... | @@ -21734,6 +21800,10 @@ fn unionFieldPtr( |
| 21734 | 21800 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 21735 | 21801 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 21736 | 21802 | } |
| 21803 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 21804 | _ = try block.addNoOp(.unreach); |
| 21805 | return Air.Inst.Ref.unreachable_value; |
| 21806 | } |
| 21737 | 21807 | return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty); |
| 21738 | 21808 | } |
| 21739 | 21809 | |
| ... | ... | @@ -21802,6 +21872,10 @@ fn unionFieldVal( |
| 21802 | 21872 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| 21803 | 21873 | try sema.addSafetyCheck(block, ok, .inactive_union_field); |
| 21804 | 21874 | } |
| 21875 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 21876 | _ = try block.addNoOp(.unreach); |
| 21877 | return Air.Inst.Ref.unreachable_value; |
| 21878 | } |
| 21805 | 21879 | return block.addStructFieldVal(union_byval, field_index, field.ty); |
| 21806 | 21880 | } |
| 21807 | 21881 | |
| ... | ... | @@ -25002,6 +25076,18 @@ fn coerceEnumToUnion( |
| 25002 | 25076 | }; |
| 25003 | 25077 | const field = union_obj.fields.values()[field_index]; |
| 25004 | 25078 | const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty); |
| 25079 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 25080 | const msg = msg: { |
| 25081 | const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); |
| 25082 | errdefer msg.destroy(sema.gpa); |
| 25083 | |
| 25084 | const field_name = union_obj.fields.keys()[field_index]; |
| 25085 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); |
| 25086 | try sema.addDeclaredHereNote(msg, union_ty); |
| 25087 | break :msg msg; |
| 25088 | }; |
| 25089 | return sema.failWithOwnedErrorMsg(msg); |
| 25090 | } |
| 25005 | 25091 | const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse { |
| 25006 | 25092 | const msg = msg: { |
| 25007 | 25093 | const field_name = union_obj.fields.keys()[field_index]; |
| ... | ... | @@ -25037,13 +25123,37 @@ fn coerceEnumToUnion( |
| 25037 | 25123 | return sema.failWithOwnedErrorMsg(msg); |
| 25038 | 25124 | } |
| 25039 | 25125 | |
| 25126 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 25127 | { |
| 25128 | var msg: ?*Module.ErrorMsg = null; |
| 25129 | errdefer if (msg) |some| some.destroy(sema.gpa); |
| 25130 | |
| 25131 | for (union_obj.fields.values()) |field, i| { |
| 25132 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 25133 | const err_msg = msg orelse try sema.errMsg( |
| 25134 | block, |
| 25135 | inst_src, |
| 25136 | "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", |
| 25137 | .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) }, |
| 25138 | ); |
| 25139 | msg = err_msg; |
| 25140 | |
| 25141 | try sema.addFieldErrNote(block, union_ty, i, err_msg, "'noreturn' field here", .{}); |
| 25142 | } |
| 25143 | } |
| 25144 | if (msg) |some| { |
| 25145 | msg = null; |
| 25146 | try sema.addDeclaredHereNote(some, union_ty); |
| 25147 | return sema.failWithOwnedErrorMsg(some); |
| 25148 | } |
| 25149 | } |
| 25150 | |
| 25040 | 25151 | // If the union has all fields 0 bits, the union value is just the enum value. |
| 25041 | 25152 | if (union_ty.unionHasAllZeroBitFieldTypes()) { |
| 25042 | 25153 | return block.addBitCast(union_ty, enum_tag); |
| 25043 | 25154 | } |
| 25044 | 25155 | |
| 25045 | 25156 | const msg = msg: { |
| 25046 | | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 25047 | 25157 | const msg = try sema.errMsg( |
| 25048 | 25158 | block, |
| 25049 | 25159 | inst_src, |
| ... | ... | @@ -25054,11 +25164,11 @@ fn coerceEnumToUnion( |
| 25054 | 25164 | |
| 25055 | 25165 | var it = union_obj.fields.iterator(); |
| 25056 | 25166 | var field_index: usize = 0; |
| 25057 | | while (it.next()) |field| { |
| 25167 | while (it.next()) |field| : (field_index += 1) { |
| 25058 | 25168 | const field_name = field.key_ptr.*; |
| 25059 | 25169 | const field_ty = field.value_ptr.ty; |
| 25170 | if (!field_ty.hasRuntimeBits()) continue; |
| 25060 | 25171 | try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); |
| 25061 | | field_index += 1; |
| 25062 | 25172 | } |
| 25063 | 25173 | try sema.addDeclaredHereNote(msg, union_ty); |
| 25064 | 25174 | break :msg msg; |
| ... | ... | @@ -25361,6 +25471,7 @@ fn coerceTupleToStruct( |
| 25361 | 25471 | |
| 25362 | 25472 | // Populate default field values and report errors for missing fields. |
| 25363 | 25473 | var root_msg: ?*Module.ErrorMsg = null; |
| 25474 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 25364 | 25475 | |
| 25365 | 25476 | for (field_refs) |*field_ref, i| { |
| 25366 | 25477 | if (field_ref.* != .none) continue; |
| ... | ... | @@ -25386,6 +25497,7 @@ fn coerceTupleToStruct( |
| 25386 | 25497 | } |
| 25387 | 25498 | |
| 25388 | 25499 | if (root_msg) |msg| { |
| 25500 | root_msg = null; |
| 25389 | 25501 | try sema.addDeclaredHereNote(msg, struct_ty); |
| 25390 | 25502 | return sema.failWithOwnedErrorMsg(msg); |
| 25391 | 25503 | } |
| ... | ... | @@ -25455,6 +25567,7 @@ fn coerceTupleToTuple( |
| 25455 | 25567 | |
| 25456 | 25568 | // Populate default field values and report errors for missing fields. |
| 25457 | 25569 | var root_msg: ?*Module.ErrorMsg = null; |
| 25570 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 25458 | 25571 | |
| 25459 | 25572 | for (field_refs) |*field_ref, i| { |
| 25460 | 25573 | if (field_ref.* != .none) continue; |
| ... | ... | @@ -25490,6 +25603,7 @@ fn coerceTupleToTuple( |
| 25490 | 25603 | } |
| 25491 | 25604 | |
| 25492 | 25605 | if (root_msg) |msg| { |
| 25606 | root_msg = null; |
| 25493 | 25607 | try sema.addDeclaredHereNote(msg, tuple_ty); |
| 25494 | 25608 | return sema.failWithOwnedErrorMsg(msg); |
| 25495 | 25609 | } |
| ... | ... | @@ -27914,6 +28028,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27914 | 28028 | }; |
| 27915 | 28029 | return sema.failWithOwnedErrorMsg(msg); |
| 27916 | 28030 | } |
| 28031 | if (field_ty.zigTypeTag() == .NoReturn) { |
| 28032 | const msg = msg: { |
| 28033 | const tree = try sema.getAstTree(&block_scope); |
| 28034 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| 28035 | const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{}); |
| 28036 | errdefer msg.destroy(sema.gpa); |
| 28037 | |
| 28038 | try sema.addDeclaredHereNote(msg, field_ty); |
| 28039 | break :msg msg; |
| 28040 | }; |
| 28041 | return sema.failWithOwnedErrorMsg(msg); |
| 28042 | } |
| 27917 | 28043 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { |
| 27918 | 28044 | const msg = msg: { |
| 27919 | 28045 | const tree = try sema.getAstTree(&block_scope); |
| ... | ... | @@ -28725,6 +28851,16 @@ fn enumFieldSrcLoc( |
| 28725 | 28851 | .container_decl_arg_trailing, |
| 28726 | 28852 | => tree.containerDeclArg(enum_node), |
| 28727 | 28853 | |
| 28854 | .tagged_union, |
| 28855 | .tagged_union_trailing, |
| 28856 | => tree.taggedUnion(enum_node), |
| 28857 | .tagged_union_two, |
| 28858 | .tagged_union_two_trailing, |
| 28859 | => tree.taggedUnionTwo(&buffer, enum_node), |
| 28860 | .tagged_union_enum_tag, |
| 28861 | .tagged_union_enum_tag_trailing, |
| 28862 | => tree.taggedUnionEnumTag(enum_node), |
| 28863 | |
| 28728 | 28864 | // Container was constructed with `@Type`. |
| 28729 | 28865 | else => return LazySrcLoc.nodeOffset(0), |
| 28730 | 28866 | }; |
| ... | ... | @@ -29375,7 +29511,9 @@ fn unionFieldAlignment( |
| 29375 | 29511 | src: LazySrcLoc, |
| 29376 | 29512 | field: Module.Union.Field, |
| 29377 | 29513 | ) !u32 { |
| 29378 | | if (field.abi_align == 0) { |
| 29514 | if (field.ty.zigTypeTag() == .NoReturn) { |
| 29515 | return @as(u32, 0); |
| 29516 | } else if (field.abi_align == 0) { |
| 29379 | 29517 | return sema.typeAbiAlignment(block, src, field.ty); |
| 29380 | 29518 | } else { |
| 29381 | 29519 | return field.abi_align; |