authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 15:07:20+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-17 22:07:48+03:00
logc3d5428cba4d02afbe1ec34bdc7bcb68f56d1b45
treecc185813723d14c8f480762ce2f9c1bda096b30b
parentb0a55e1b3be3a274546f9c18016e9609d546bdb0

Sema: properly handle noreturn fields in unions


5 files changed, 270 insertions(+), 34 deletions(-)

src/Sema.zig+170-32
...@@ -3772,6 +3772,7 @@ fn validateStructInit(...@@ -3772,6 +3772,7 @@ fn validateStructInit(
3772 }3772 }
37733773
3774 var root_msg: ?*Module.ErrorMsg = null;3774 var root_msg: ?*Module.ErrorMsg = null;
3775 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
37753776
3776 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);3777 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
3777 if ((is_comptime or block.is_comptime) and3778 if ((is_comptime or block.is_comptime) and
...@@ -3947,6 +3948,7 @@ fn validateStructInit(...@@ -3947,6 +3948,7 @@ fn validateStructInit(
3947 }3948 }
39483949
3949 if (root_msg) |msg| {3950 if (root_msg) |msg| {
3951 root_msg = null;
3950 if (struct_ty.castTag(.@"struct")) |struct_obj| {3952 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3951 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);3953 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
3952 defer gpa.free(fqn);3954 defer gpa.free(fqn);
...@@ -4005,6 +4007,8 @@ fn zirValidateArrayInit(...@@ -4005,6 +4007,8 @@ fn zirValidateArrayInit(
4005 if (instrs.len != array_len and array_ty.isTuple()) {4007 if (instrs.len != array_len and array_ty.isTuple()) {
4006 const struct_obj = array_ty.castTag(.tuple).?.data;4008 const struct_obj = array_ty.castTag(.tuple).?.data;
4007 var root_msg: ?*Module.ErrorMsg = null;4009 var root_msg: ?*Module.ErrorMsg = null;
4010 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
4011
4008 for (struct_obj.values) |default_val, i| {4012 for (struct_obj.values) |default_val, i| {
4009 if (i < instrs.len) continue;4013 if (i < instrs.len) continue;
40104014
...@@ -4019,6 +4023,7 @@ fn zirValidateArrayInit(...@@ -4019,6 +4023,7 @@ fn zirValidateArrayInit(
4019 }4023 }
40204024
4021 if (root_msg) |msg| {4025 if (root_msg) |msg| {
4026 root_msg = null;
4022 return sema.failWithOwnedErrorMsg(msg);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,12 +8969,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8964 },8969 },
8965 };8970 };
89668971
8967 const union_originally = blk: {8972 const maybe_union_ty = blk: {
8968 const zir_data = sema.code.instructions.items(.data);8973 const zir_data = sema.code.instructions.items(.data);
8969 const cond_index = Zir.refToIndex(extra.data.operand).?;8974 const cond_index = Zir.refToIndex(extra.data.operand).?;
8970 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;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);
89738981
8974 const operand_ty = sema.typeOf(operand);8982 const operand_ty = sema.typeOf(operand);
89758983
...@@ -9004,7 +9012,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9004,7 +9012,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9004 .Union => unreachable, // handled in zirSwitchCond9012 .Union => unreachable, // handled in zirSwitchCond
9005 .Enum => {9013 .Enum => {
9006 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());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 mem.set(?Module.SwitchProngSrc, seen_fields, null);9017 mem.set(?Module.SwitchProngSrc, seen_fields, null);
90099018
9010 // This is used for non-exhaustive enum values that do not correspond to any tags.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,18 +9646,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9637 const item = try sema.resolveInst(item_ref);9646 const item = try sema.resolveInst(item_ref);
9638 // `item` is already guaranteed to be constant known.9647 // `item` is already guaranteed to be constant known.
96399648
9640 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9649 const analyze_body = if (union_originally) blk: {
9641 error.ComptimeBreak => {9650 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9642 const zir_datas = sema.code.instructions.items(.data);9651 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9643 const break_data = zir_datas[sema.comptime_break_inst].@"break";9652 break :blk field_ty.zigTypeTag() != .NoReturn;
9644 try sema.addRuntimeBreak(&case_block, .{9653 } else true;
9645 .block_inst = break_data.block_inst,9654
9646 .operand = break_data.operand,9655 if (analyze_body) {
9647 .inst = sema.comptime_break_inst,9656 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9648 });9657 error.ComptimeBreak => {
9649 },9658 const zir_datas = sema.code.instructions.items(.data);
9650 else => |e| return e,9659 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9651 };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 }
96529671
9653 try wip_captures.finalize();9672 try wip_captures.finalize();
96549673
...@@ -9689,20 +9708,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9689,20 +9708,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9689 if (ranges_len == 0) {9708 if (ranges_len == 0) {
9690 cases_len += 1;9709 cases_len += 1;
96919710
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 const body = sema.code.extra[extra_index..][0..body_len];9721 const body = sema.code.extra[extra_index..][0..body_len];
9693 extra_index += body_len;9722 extra_index += body_len;
9694 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9723 if (analyze_body) {
9695 error.ComptimeBreak => {9724 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9696 const zir_datas = sema.code.instructions.items(.data);9725 error.ComptimeBreak => {
9697 const break_data = zir_datas[sema.comptime_break_inst].@"break";9726 const zir_datas = sema.code.instructions.items(.data);
9698 try sema.addRuntimeBreak(&case_block, .{9727 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9699 .block_inst = break_data.block_inst,9728 try sema.addRuntimeBreak(&case_block, .{
9700 .operand = break_data.operand,9729 .block_inst = break_data.block_inst,
9701 .inst = sema.comptime_break_inst,9730 .operand = break_data.operand,
9702 });9731 .inst = sema.comptime_break_inst,
9703 },9732 });
9704 else => |e| return e,9733 },
9705 };9734 else => |e| return e,
9735 };
9736 } else {
9737 _ = try case_block.addNoOp(.unreach);
9738 }
97069739
9707 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +9740 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
9708 case_block.instructions.items.len);9741 case_block.instructions.items.len);
...@@ -9824,7 +9857,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9824,7 +9857,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9824 case_block.instructions.shrinkRetainingCapacity(0);9857 case_block.instructions.shrinkRetainingCapacity(0);
9825 case_block.wip_capture_scope = wip_captures.scope;9858 case_block.wip_capture_scope = wip_captures.scope;
98269859
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 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {9871 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
9829 error.ComptimeBreak => {9872 error.ComptimeBreak => {
9830 const zir_datas = sema.code.instructions.items(.data);9873 const zir_datas = sema.code.instructions.items(.data);
...@@ -13225,6 +13268,14 @@ fn analyzeCmpUnionTag(...@@ -13225,6 +13268,14 @@ fn analyzeCmpUnionTag(
13225 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);13268 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
13226 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);13269 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
1322713270
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 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);13279 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
13229}13280}
1323013281
...@@ -15579,6 +15630,8 @@ fn finishStructInit(...@@ -15579,6 +15630,8 @@ fn finishStructInit(
15579 const gpa = sema.gpa;15630 const gpa = sema.gpa;
1558015631
15581 var root_msg: ?*Module.ErrorMsg = null;15632 var root_msg: ?*Module.ErrorMsg = null;
15633 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
15634
15582 if (struct_ty.isAnonStruct()) {15635 if (struct_ty.isAnonStruct()) {
15583 const struct_obj = struct_ty.castTag(.anon_struct).?.data;15636 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
15584 for (struct_obj.values) |default_val, i| {15637 for (struct_obj.values) |default_val, i| {
...@@ -15634,6 +15687,7 @@ fn finishStructInit(...@@ -15634,6 +15687,7 @@ fn finishStructInit(
15634 }15687 }
1563515688
15636 if (root_msg) |msg| {15689 if (root_msg) |msg| {
15690 root_msg = null;
15637 if (struct_ty.castTag(.@"struct")) |struct_obj| {15691 if (struct_ty.castTag(.@"struct")) |struct_obj| {
15638 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);15692 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
15639 defer gpa.free(fqn);15693 defer gpa.free(fqn);
...@@ -21682,6 +21736,18 @@ fn unionFieldPtr(...@@ -21682,6 +21736,18 @@ fn unionFieldPtr(
21682 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),21736 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
21683 });21737 });
2168421738
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 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {21751 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
21686 switch (union_obj.layout) {21752 switch (union_obj.layout) {
21687 .Auto => if (!initializing) {21753 .Auto => if (!initializing) {
...@@ -21734,6 +21800,10 @@ fn unionFieldPtr(...@@ -21734,6 +21800,10 @@ fn unionFieldPtr(
21734 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21800 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21735 try sema.addSafetyCheck(block, ok, .inactive_union_field);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 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);21807 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
21738}21808}
2173921809
...@@ -21802,6 +21872,10 @@ fn unionFieldVal(...@@ -21802,6 +21872,10 @@ fn unionFieldVal(
21802 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21872 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21803 try sema.addSafetyCheck(block, ok, .inactive_union_field);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 return block.addStructFieldVal(union_byval, field_index, field.ty);21879 return block.addStructFieldVal(union_byval, field_index, field.ty);
21806}21880}
2180721881
...@@ -25002,6 +25076,18 @@ fn coerceEnumToUnion(...@@ -25002,6 +25076,18 @@ fn coerceEnumToUnion(
25002 };25076 };
25003 const field = union_obj.fields.values()[field_index];25077 const field = union_obj.fields.values()[field_index];
25004 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);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 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {25091 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
25006 const msg = msg: {25092 const msg = msg: {
25007 const field_name = union_obj.fields.keys()[field_index];25093 const field_name = union_obj.fields.keys()[field_index];
...@@ -25037,13 +25123,37 @@ fn coerceEnumToUnion(...@@ -25037,13 +25123,37 @@ fn coerceEnumToUnion(
25037 return sema.failWithOwnedErrorMsg(msg);25123 return sema.failWithOwnedErrorMsg(msg);
25038 }25124 }
2503925125
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 // If the union has all fields 0 bits, the union value is just the enum value.25151 // If the union has all fields 0 bits, the union value is just the enum value.
25041 if (union_ty.unionHasAllZeroBitFieldTypes()) {25152 if (union_ty.unionHasAllZeroBitFieldTypes()) {
25042 return block.addBitCast(union_ty, enum_tag);25153 return block.addBitCast(union_ty, enum_tag);
25043 }25154 }
2504425155
25045 const msg = msg: {25156 const msg = msg: {
25046 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
25047 const msg = try sema.errMsg(25157 const msg = try sema.errMsg(
25048 block,25158 block,
25049 inst_src,25159 inst_src,
...@@ -25054,11 +25164,11 @@ fn coerceEnumToUnion(...@@ -25054,11 +25164,11 @@ fn coerceEnumToUnion(
2505425164
25055 var it = union_obj.fields.iterator();25165 var it = union_obj.fields.iterator();
25056 var field_index: usize = 0;25166 var field_index: usize = 0;
25057 while (it.next()) |field| {25167 while (it.next()) |field| : (field_index += 1) {
25058 const field_name = field.key_ptr.*;25168 const field_name = field.key_ptr.*;
25059 const field_ty = field.value_ptr.ty;25169 const field_ty = field.value_ptr.ty;
25170 if (!field_ty.hasRuntimeBits()) continue;
25060 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });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 try sema.addDeclaredHereNote(msg, union_ty);25173 try sema.addDeclaredHereNote(msg, union_ty);
25064 break :msg msg;25174 break :msg msg;
...@@ -25361,6 +25471,7 @@ fn coerceTupleToStruct(...@@ -25361,6 +25471,7 @@ fn coerceTupleToStruct(
2536125471
25362 // Populate default field values and report errors for missing fields.25472 // Populate default field values and report errors for missing fields.
25363 var root_msg: ?*Module.ErrorMsg = null;25473 var root_msg: ?*Module.ErrorMsg = null;
25474 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2536425475
25365 for (field_refs) |*field_ref, i| {25476 for (field_refs) |*field_ref, i| {
25366 if (field_ref.* != .none) continue;25477 if (field_ref.* != .none) continue;
...@@ -25386,6 +25497,7 @@ fn coerceTupleToStruct(...@@ -25386,6 +25497,7 @@ fn coerceTupleToStruct(
25386 }25497 }
2538725498
25388 if (root_msg) |msg| {25499 if (root_msg) |msg| {
25500 root_msg = null;
25389 try sema.addDeclaredHereNote(msg, struct_ty);25501 try sema.addDeclaredHereNote(msg, struct_ty);
25390 return sema.failWithOwnedErrorMsg(msg);25502 return sema.failWithOwnedErrorMsg(msg);
25391 }25503 }
...@@ -25455,6 +25567,7 @@ fn coerceTupleToTuple(...@@ -25455,6 +25567,7 @@ fn coerceTupleToTuple(
2545525567
25456 // Populate default field values and report errors for missing fields.25568 // Populate default field values and report errors for missing fields.
25457 var root_msg: ?*Module.ErrorMsg = null;25569 var root_msg: ?*Module.ErrorMsg = null;
25570 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2545825571
25459 for (field_refs) |*field_ref, i| {25572 for (field_refs) |*field_ref, i| {
25460 if (field_ref.* != .none) continue;25573 if (field_ref.* != .none) continue;
...@@ -25490,6 +25603,7 @@ fn coerceTupleToTuple(...@@ -25490,6 +25603,7 @@ fn coerceTupleToTuple(
25490 }25603 }
2549125604
25492 if (root_msg) |msg| {25605 if (root_msg) |msg| {
25606 root_msg = null;
25493 try sema.addDeclaredHereNote(msg, tuple_ty);25607 try sema.addDeclaredHereNote(msg, tuple_ty);
25494 return sema.failWithOwnedErrorMsg(msg);25608 return sema.failWithOwnedErrorMsg(msg);
25495 }25609 }
...@@ -27914,6 +28028,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27914,6 +28028,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27914 };28028 };
27915 return sema.failWithOwnedErrorMsg(msg);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 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {28043 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
27918 const msg = msg: {28044 const msg = msg: {
27919 const tree = try sema.getAstTree(&block_scope);28045 const tree = try sema.getAstTree(&block_scope);
...@@ -28725,6 +28851,16 @@ fn enumFieldSrcLoc(...@@ -28725,6 +28851,16 @@ fn enumFieldSrcLoc(
28725 .container_decl_arg_trailing,28851 .container_decl_arg_trailing,
28726 => tree.containerDeclArg(enum_node),28852 => tree.containerDeclArg(enum_node),
2872728853
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 // Container was constructed with `@Type`.28864 // Container was constructed with `@Type`.
28729 else => return LazySrcLoc.nodeOffset(0),28865 else => return LazySrcLoc.nodeOffset(0),
28730 };28866 };
...@@ -29375,7 +29511,9 @@ fn unionFieldAlignment(...@@ -29375,7 +29511,9 @@ fn unionFieldAlignment(
29375 src: LazySrcLoc,29511 src: LazySrcLoc,
29376 field: Module.Union.Field,29512 field: Module.Union.Field,
29377) !u32 {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 return sema.typeAbiAlignment(block, src, field.ty);29517 return sema.typeAbiAlignment(block, src, field.ty);
29380 } else {29518 } else {
29381 return field.abi_align;29519 return field.abi_align;
test/behavior/union.zig+45
...@@ -1256,3 +1256,48 @@ test "return an extern union from C calling convention" {...@@ -1256,3 +1256,48 @@ test "return an extern union from C calling convention" {
1256 });1256 });
1257 try expect(u.d == 4.0);1257 try expect(u.d == 4.0);
1258}1258}
1259
1260test "noreturn field in union" {
1261 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1264 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1265
1266 const U = union(enum) {
1267 a: u32,
1268 b: noreturn,
1269 c: noreturn,
1270 };
1271 var a = U{ .a = 1 };
1272 var count: u32 = 0;
1273 if (a == .b) @compileError("bad");
1274 switch (a) {
1275 .a => count += 1,
1276 .b => |val| {
1277 _ = val;
1278 @compileError("bad");
1279 },
1280 .c => @compileError("bad"),
1281 }
1282 switch (a) {
1283 .a => count += 1,
1284 .b, .c => @compileError("bad"),
1285 }
1286 switch (a) {
1287 .a, .b, .c => {
1288 count += 1;
1289 try expect(a == .a);
1290 },
1291 }
1292 switch (a) {
1293 .a => count += 1,
1294 else => @compileError("bad"),
1295 }
1296 switch (a) {
1297 else => {
1298 count += 1;
1299 try expect(a == .a);
1300 },
1301 }
1302 try expect(count == 5);
1303}
test/cases/compile_errors/noreturn_struct_field.zig created+12
...@@ -0,0 +1,12 @@
1const S = struct {
2 s: noreturn,
3};
4comptime {
5 _ = @typeInfo(S);
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:5: error: struct fields cannot be 'noreturn'
test/cases/compile_errors/runtime_cast_to_union_which_has_non-void_fields.zig-2
...@@ -18,6 +18,4 @@ fn foo(l: Letter) void {...@@ -18,6 +18,4 @@ fn foo(l: Letter) void {
18//18//
19// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields19// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields
20// :3:5: note: field 'A' has type 'i32'20// :3:5: note: field 'A' has type 'i32'
21// :4:5: note: field 'B' has type 'void'
22// :5:5: note: field 'C' has type 'void'
23// :2:15: note: union declared here21// :2:15: note: union declared here
test/cases/compile_errors/union_noreturn_field_initialized.zig created+43
...@@ -0,0 +1,43 @@
1pub export fn entry1() void {
2 const U = union(enum) {
3 a: u32,
4 b: noreturn,
5 fn foo(_: @This()) void {}
6 fn bar() noreturn {
7 unreachable;
8 }
9 };
10
11 var a = U{ .b = undefined };
12 _ = a;
13}
14pub export fn entry2() void {
15 const U = union(enum) {
16 a: noreturn,
17 };
18 var u: U = undefined;
19 u = .a;
20}
21pub export fn entry3() void {
22 const U = union(enum) {
23 a: noreturn,
24 b: void,
25 };
26 var e = @typeInfo(U).Union.tag_type.?.a;
27 var u: U = undefined;
28 u = e;
29}
30
31// error
32// backend=stage2
33// target=native
34//
35// :11:21: error: cannot initialize 'noreturn' field of union
36// :4:9: note: field 'b' declared here
37// :2:15: note: union declared here
38// :19:10: error: cannot initialize 'noreturn' field of union
39// :16:9: note: field 'a' declared here
40// :15:15: note: union declared here
41// :28:9: error: runtime coercion from enum '@typeInfo(tmp.entry3.U).Union.tag_type.?' to union 'tmp.entry3.U' which has a 'noreturn' field
42// :23:9: note: 'noreturn' field here
43// :22:15: note: union declared here