authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-18 17:18:57+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-18 17:18:57+03:00
logb038dba06bfcedd9691142c6715884b7384623c2
treeeca544d3da4db957164858fb7de1334657263fe0
parent4f2143beccb822f42c77d1d6c5ad31388123803e
parent233049503a41ac4c6895f7126cda63349606b8f8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12462 from Vexu/stage2-noreturn

Stage2: improve behavior of noreturn

21 files changed, 573 insertions(+), 212 deletions(-)

src/AstGen.zig-9
......@@ -4557,9 +4557,6 @@ fn unionDeclInner(
45574557 wip_members.appendToField(@enumToInt(tag_value));
45584558 }
45594559 }
4560 if (field_count == 0) {
4561 return astgen.failNode(node, "union declarations must have at least one tag", .{});
4562 }
45634560
45644561 if (!block_scope.isEmpty()) {
45654562 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
......@@ -4715,12 +4712,6 @@ fn containerDecl(
47154712 .nonexhaustive_node = nonexhaustive_node,
47164713 };
47174714 };
4718 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) {
4719 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
4720 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
4721 // must be at least one tag.
4722 try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{});
4723 }
47244715 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
47254716 try astgen.appendErrorNodeNotes(
47264717 node,
src/Sema.zig+281-118
......@@ -3773,6 +3773,7 @@ fn validateStructInit(
37733773 }
37743774
37753775 var root_msg: ?*Module.ErrorMsg = null;
3776 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
37763777
37773778 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
37783779 if ((is_comptime or block.is_comptime) and
......@@ -3948,6 +3949,7 @@ fn validateStructInit(
39483949 }
39493950
39503951 if (root_msg) |msg| {
3952 root_msg = null;
39513953 if (struct_ty.castTag(.@"struct")) |struct_obj| {
39523954 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
39533955 defer gpa.free(fqn);
......@@ -4006,6 +4008,8 @@ fn zirValidateArrayInit(
40064008 if (instrs.len != array_len and array_ty.isTuple()) {
40074009 const struct_obj = array_ty.castTag(.tuple).?.data;
40084010 var root_msg: ?*Module.ErrorMsg = null;
4011 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
4012
40094013 for (struct_obj.values) |default_val, i| {
40104014 if (i < instrs.len) continue;
40114015
......@@ -4020,6 +4024,7 @@ fn zirValidateArrayInit(
40204024 }
40214025
40224026 if (root_msg) |msg| {
4027 root_msg = null;
40234028 return sema.failWithOwnedErrorMsg(msg);
40244029 }
40254030 }
......@@ -6702,8 +6707,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
67026707 defer tracy.end();
67036708
67046709 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6705 const src = inst_data.src();
6706 const child_type = try sema.resolveType(block, src, inst_data.operand);
6710 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
6711 const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
6712 if (child_type.zigTypeTag() == .Opaque) {
6713 return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
6714 } else if (child_type.zigTypeTag() == .Null) {
6715 return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
6716 }
67076717 const opt_type = try Type.optional(sema.arena, child_type);
67086718
67096719 return sema.addType(opt_type);
......@@ -6802,6 +6812,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
68026812 error_set.fmt(sema.mod),
68036813 });
68046814 }
6815 if (payload.zigTypeTag() == .Opaque) {
6816 return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
6817 payload.fmt(sema.mod),
6818 });
6819 } else if (payload.zigTypeTag() == .ErrorSet) {
6820 return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
6821 payload.fmt(sema.mod),
6822 });
6823 }
68056824 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
68066825 return sema.addType(err_union_ty);
68076826}
......@@ -8968,12 +8987,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
89688987 },
89698988 };
89708989
8971 const union_originally = blk: {
8990 const maybe_union_ty = blk: {
89728991 const zir_data = sema.code.instructions.items(.data);
89738992 const cond_index = Zir.refToIndex(extra.data.operand).?;
89748993 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
8975 break :blk sema.typeOf(raw_operand).zigTypeTag() == .Union;
8994 break :blk sema.typeOf(raw_operand);
89768995 };
8996 const union_originally = maybe_union_ty.zigTypeTag() == .Union;
8997 var seen_union_fields: []?Module.SwitchProngSrc = &.{};
8998 defer gpa.free(seen_union_fields);
8999
9000 var empty_enum = false;
89779001
89789002 const operand_ty = sema.typeOf(operand);
89799003
......@@ -9008,7 +9032,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
90089032 .Union => unreachable, // handled in zirSwitchCond
90099033 .Enum => {
90109034 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
9011 defer gpa.free(seen_fields);
9035 empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
9036 defer if (!union_originally) gpa.free(seen_fields);
9037 if (union_originally) seen_union_fields = seen_fields;
90129038 mem.set(?Module.SwitchProngSrc, seen_fields, null);
90139039
90149040 // This is used for non-exhaustive enum values that do not correspond to any tags.
......@@ -9602,6 +9628,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
96029628 }
96039629
96049630 if (scalar_cases_len + multi_cases_len == 0) {
9631 if (empty_enum) {
9632 return Air.Inst.Ref.void_value;
9633 }
96059634 if (special_prong == .none) {
96069635 return sema.fail(block, src, "switch must handle all possibilities", .{});
96079636 }
......@@ -9641,18 +9670,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
96419670 const item = try sema.resolveInst(item_ref);
96429671 // `item` is already guaranteed to be constant known.
96439672
9644 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9645 error.ComptimeBreak => {
9646 const zir_datas = sema.code.instructions.items(.data);
9647 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9648 try sema.addRuntimeBreak(&case_block, .{
9649 .block_inst = break_data.block_inst,
9650 .operand = break_data.operand,
9651 .inst = sema.comptime_break_inst,
9652 });
9653 },
9654 else => |e| return e,
9655 };
9673 const analyze_body = if (union_originally) blk: {
9674 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9675 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9676 break :blk field_ty.zigTypeTag() != .NoReturn;
9677 } else true;
9678
9679 if (analyze_body) {
9680 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9681 error.ComptimeBreak => {
9682 const zir_datas = sema.code.instructions.items(.data);
9683 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9684 try sema.addRuntimeBreak(&case_block, .{
9685 .block_inst = break_data.block_inst,
9686 .operand = break_data.operand,
9687 .inst = sema.comptime_break_inst,
9688 });
9689 },
9690 else => |e| return e,
9691 };
9692 } else {
9693 _ = try case_block.addNoOp(.unreach);
9694 }
96569695
96579696 try wip_captures.finalize();
96589697
......@@ -9693,20 +9732,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
96939732 if (ranges_len == 0) {
96949733 cases_len += 1;
96959734
9735 const analyze_body = if (union_originally)
9736 for (items) |item_ref| {
9737 const item = try sema.resolveInst(item_ref);
9738 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9739 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9740 if (field_ty.zigTypeTag() != .NoReturn) break true;
9741 } else false
9742 else
9743 true;
9744
96969745 const body = sema.code.extra[extra_index..][0..body_len];
96979746 extra_index += body_len;
9698 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9699 error.ComptimeBreak => {
9700 const zir_datas = sema.code.instructions.items(.data);
9701 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9702 try sema.addRuntimeBreak(&case_block, .{
9703 .block_inst = break_data.block_inst,
9704 .operand = break_data.operand,
9705 .inst = sema.comptime_break_inst,
9706 });
9707 },
9708 else => |e| return e,
9709 };
9747 if (analyze_body) {
9748 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9749 error.ComptimeBreak => {
9750 const zir_datas = sema.code.instructions.items(.data);
9751 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9752 try sema.addRuntimeBreak(&case_block, .{
9753 .block_inst = break_data.block_inst,
9754 .operand = break_data.operand,
9755 .inst = sema.comptime_break_inst,
9756 });
9757 },
9758 else => |e| return e,
9759 };
9760 } else {
9761 _ = try case_block.addNoOp(.unreach);
9762 }
97109763
97119764 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
97129765 case_block.instructions.items.len);
......@@ -9828,7 +9881,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
98289881 case_block.instructions.shrinkRetainingCapacity(0);
98299882 case_block.wip_capture_scope = wip_captures.scope;
98309883
9831 if (special.body.len != 0) {
9884 const analyze_body = if (union_originally)
9885 for (seen_union_fields) |seen_field, index| {
9886 if (seen_field != null) continue;
9887 const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;
9888 const field_ty = union_obj.fields.values()[index].ty;
9889 if (field_ty.zigTypeTag() != .NoReturn) break true;
9890 } else false
9891 else
9892 true;
9893
9894 if (special.body.len != 0 and analyze_body) {
98329895 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
98339896 error.ComptimeBreak => {
98349897 const zir_datas = sema.code.instructions.items(.data);
......@@ -13244,6 +13307,14 @@ fn analyzeCmpUnionTag(
1324413307 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
1324513308 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
1324613309
13310 if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| {
13311 if (enum_val.isUndef()) return sema.addConstUndef(Type.bool);
13312 const field_ty = union_ty.unionFieldType(enum_val, sema.mod);
13313 if (field_ty.zigTypeTag() == .NoReturn) {
13314 return Air.Inst.Ref.bool_false;
13315 }
13316 }
13317
1324713318 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
1324813319}
1324913320
......@@ -15598,6 +15669,8 @@ fn finishStructInit(
1559815669 const gpa = sema.gpa;
1559915670
1560015671 var root_msg: ?*Module.ErrorMsg = null;
15672 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
15673
1560115674 if (struct_ty.isAnonStruct()) {
1560215675 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
1560315676 for (struct_obj.values) |default_val, i| {
......@@ -15653,6 +15726,7 @@ fn finishStructInit(
1565315726 }
1565415727
1565515728 if (root_msg) |msg| {
15729 root_msg = null;
1565615730 if (struct_ty.castTag(.@"struct")) |struct_obj| {
1565715731 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
1565815732 defer gpa.free(fqn);
......@@ -16655,43 +16729,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1665516729
1665616730 // Fields
1665716731 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
16658 if (fields_len > 0) {
16659 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16660 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16661 .ty = enum_obj.tag_ty,
16662 .mod = mod,
16663 });
16664
16665 var i: usize = 0;
16666 while (i < fields_len) : (i += 1) {
16667 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16668 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16669 // TODO use reflection instead of magic numbers here
16670 // name: []const u8
16671 const name_val = field_struct_val[0];
16672 // value: comptime_int
16673 const value_val = field_struct_val[1];
16674
16675 const field_name = try name_val.toAllocatedBytes(
16676 Type.initTag(.const_slice_u8),
16677 new_decl_arena_allocator,
16678 sema.mod,
16679 );
16732 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16733 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16734 .ty = enum_obj.tag_ty,
16735 .mod = mod,
16736 });
1668016737
16681 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16682 if (gop.found_existing) {
16683 // TODO: better source location
16684 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
16685 }
16738 var i: usize = 0;
16739 while (i < fields_len) : (i += 1) {
16740 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16741 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16742 // TODO use reflection instead of magic numbers here
16743 // name: []const u8
16744 const name_val = field_struct_val[0];
16745 // value: comptime_int
16746 const value_val = field_struct_val[1];
16747
16748 const field_name = try name_val.toAllocatedBytes(
16749 Type.initTag(.const_slice_u8),
16750 new_decl_arena_allocator,
16751 sema.mod,
16752 );
1668616753
16687 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
16688 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
16689 .ty = enum_obj.tag_ty,
16690 .mod = mod,
16691 });
16754 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16755 if (gop.found_existing) {
16756 // TODO: better source location
16757 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
1669216758 }
16693 } else {
16694 return sema.fail(block, src, "enums must have at least one field", .{});
16759
16760 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
16761 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
16762 .ty = enum_obj.tag_ty,
16763 .mod = mod,
16764 });
1669516765 }
1669616766
1669716767 try new_decl.finalizeNewArena(&new_decl_arena);
......@@ -16816,58 +16886,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1681616886 }
1681716887
1681816888 // Fields
16819 if (fields_len > 0) {
16820 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16889 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1682116890
16822 var i: usize = 0;
16823 while (i < fields_len) : (i += 1) {
16824 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16825 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16826 // TODO use reflection instead of magic numbers here
16827 // name: []const u8
16828 const name_val = field_struct_val[0];
16829 // field_type: type,
16830 const field_type_val = field_struct_val[1];
16831 // alignment: comptime_int,
16832 const alignment_val = field_struct_val[2];
16833
16834 const field_name = try name_val.toAllocatedBytes(
16835 Type.initTag(.const_slice_u8),
16836 new_decl_arena_allocator,
16837 sema.mod,
16838 );
16891 var i: usize = 0;
16892 while (i < fields_len) : (i += 1) {
16893 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16894 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16895 // TODO use reflection instead of magic numbers here
16896 // name: []const u8
16897 const name_val = field_struct_val[0];
16898 // field_type: type,
16899 const field_type_val = field_struct_val[1];
16900 // alignment: comptime_int,
16901 const alignment_val = field_struct_val[2];
1683916902
16840 if (enum_field_names) |set| {
16841 set.putAssumeCapacity(field_name, {});
16842 }
16903 const field_name = try name_val.toAllocatedBytes(
16904 Type.initTag(.const_slice_u8),
16905 new_decl_arena_allocator,
16906 sema.mod,
16907 );
1684316908
16844 if (tag_ty_field_names) |*names| {
16845 const enum_has_field = names.orderedRemove(field_name);
16846 if (!enum_has_field) {
16847 const msg = msg: {
16848 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
16849 errdefer msg.destroy(sema.gpa);
16850 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
16851 break :msg msg;
16852 };
16853 return sema.failWithOwnedErrorMsg(msg);
16854 }
16855 }
16909 if (enum_field_names) |set| {
16910 set.putAssumeCapacity(field_name, {});
16911 }
1685616912
16857 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16858 if (gop.found_existing) {
16859 // TODO: better source location
16860 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
16913 if (tag_ty_field_names) |*names| {
16914 const enum_has_field = names.orderedRemove(field_name);
16915 if (!enum_has_field) {
16916 const msg = msg: {
16917 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
16918 errdefer msg.destroy(sema.gpa);
16919 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
16920 break :msg msg;
16921 };
16922 return sema.failWithOwnedErrorMsg(msg);
1686116923 }
16924 }
1686216925
16863 var buffer: Value.ToTypeBuffer = undefined;
16864 gop.value_ptr.* = .{
16865 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
16866 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
16867 };
16926 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16927 if (gop.found_existing) {
16928 // TODO: better source location
16929 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
1686816930 }
16869 } else {
16870 return sema.fail(block, src, "unions must have at least one field", .{});
16931
16932 var buffer: Value.ToTypeBuffer = undefined;
16933 gop.value_ptr.* = .{
16934 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
16935 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
16936 };
1687116937 }
1687216938
1687316939 if (tag_ty_field_names) |names| {
......@@ -21701,6 +21767,18 @@ fn unionFieldPtr(
2170121767 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
2170221768 });
2170321769
21770 if (initializing and field.ty.zigTypeTag() == .NoReturn) {
21771 const msg = msg: {
21772 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
21773 errdefer msg.destroy(sema.gpa);
21774
21775 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
21776 try sema.addDeclaredHereNote(msg, union_ty);
21777 break :msg msg;
21778 };
21779 return sema.failWithOwnedErrorMsg(msg);
21780 }
21781
2170421782 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
2170521783 switch (union_obj.layout) {
2170621784 .Auto => if (!initializing) {
......@@ -21753,6 +21831,10 @@ fn unionFieldPtr(
2175321831 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2175421832 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2175521833 }
21834 if (field.ty.zigTypeTag() == .NoReturn) {
21835 _ = try block.addNoOp(.unreach);
21836 return Air.Inst.Ref.unreachable_value;
21837 }
2175621838 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
2175721839}
2175821840
......@@ -21821,6 +21903,10 @@ fn unionFieldVal(
2182121903 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2182221904 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2182321905 }
21906 if (field.ty.zigTypeTag() == .NoReturn) {
21907 _ = try block.addNoOp(.unreach);
21908 return Air.Inst.Ref.unreachable_value;
21909 }
2182421910 return block.addStructFieldVal(union_byval, field_index, field.ty);
2182521911}
2182621912
......@@ -25021,6 +25107,18 @@ fn coerceEnumToUnion(
2502125107 };
2502225108 const field = union_obj.fields.values()[field_index];
2502325109 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);
25110 if (field_ty.zigTypeTag() == .NoReturn) {
25111 const msg = msg: {
25112 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
25113 errdefer msg.destroy(sema.gpa);
25114
25115 const field_name = union_obj.fields.keys()[field_index];
25116 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
25117 try sema.addDeclaredHereNote(msg, union_ty);
25118 break :msg msg;
25119 };
25120 return sema.failWithOwnedErrorMsg(msg);
25121 }
2502425122 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
2502525123 const msg = msg: {
2502625124 const field_name = union_obj.fields.keys()[field_index];
......@@ -25056,13 +25154,37 @@ fn coerceEnumToUnion(
2505625154 return sema.failWithOwnedErrorMsg(msg);
2505725155 }
2505825156
25157 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
25158 {
25159 var msg: ?*Module.ErrorMsg = null;
25160 errdefer if (msg) |some| some.destroy(sema.gpa);
25161
25162 for (union_obj.fields.values()) |field, i| {
25163 if (field.ty.zigTypeTag() == .NoReturn) {
25164 const err_msg = msg orelse try sema.errMsg(
25165 block,
25166 inst_src,
25167 "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field",
25168 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
25169 );
25170 msg = err_msg;
25171
25172 try sema.addFieldErrNote(block, union_ty, i, err_msg, "'noreturn' field here", .{});
25173 }
25174 }
25175 if (msg) |some| {
25176 msg = null;
25177 try sema.addDeclaredHereNote(some, union_ty);
25178 return sema.failWithOwnedErrorMsg(some);
25179 }
25180 }
25181
2505925182 // If the union has all fields 0 bits, the union value is just the enum value.
2506025183 if (union_ty.unionHasAllZeroBitFieldTypes()) {
2506125184 return block.addBitCast(union_ty, enum_tag);
2506225185 }
2506325186
2506425187 const msg = msg: {
25065 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2506625188 const msg = try sema.errMsg(
2506725189 block,
2506825190 inst_src,
......@@ -25073,11 +25195,11 @@ fn coerceEnumToUnion(
2507325195
2507425196 var it = union_obj.fields.iterator();
2507525197 var field_index: usize = 0;
25076 while (it.next()) |field| {
25198 while (it.next()) |field| : (field_index += 1) {
2507725199 const field_name = field.key_ptr.*;
2507825200 const field_ty = field.value_ptr.ty;
25201 if (!field_ty.hasRuntimeBits()) continue;
2507925202 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
25080 field_index += 1;
2508125203 }
2508225204 try sema.addDeclaredHereNote(msg, union_ty);
2508325205 break :msg msg;
......@@ -25380,6 +25502,7 @@ fn coerceTupleToStruct(
2538025502
2538125503 // Populate default field values and report errors for missing fields.
2538225504 var root_msg: ?*Module.ErrorMsg = null;
25505 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2538325506
2538425507 for (field_refs) |*field_ref, i| {
2538525508 if (field_ref.* != .none) continue;
......@@ -25405,6 +25528,7 @@ fn coerceTupleToStruct(
2540525528 }
2540625529
2540725530 if (root_msg) |msg| {
25531 root_msg = null;
2540825532 try sema.addDeclaredHereNote(msg, struct_ty);
2540925533 return sema.failWithOwnedErrorMsg(msg);
2541025534 }
......@@ -25474,6 +25598,7 @@ fn coerceTupleToTuple(
2547425598
2547525599 // Populate default field values and report errors for missing fields.
2547625600 var root_msg: ?*Module.ErrorMsg = null;
25601 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2547725602
2547825603 for (field_refs) |*field_ref, i| {
2547925604 if (field_ref.* != .none) continue;
......@@ -25509,6 +25634,7 @@ fn coerceTupleToTuple(
2550925634 }
2551025635
2551125636 if (root_msg) |msg| {
25637 root_msg = null;
2551225638 try sema.addDeclaredHereNote(msg, tuple_ty);
2551325639 return sema.failWithOwnedErrorMsg(msg);
2551425640 }
......@@ -25747,6 +25873,12 @@ fn analyzeIsNull(
2574725873 return Air.Inst.Ref.bool_false;
2574825874 }
2574925875 }
25876
25877 const operand_ty = sema.typeOf(operand);
25878 var buf: Type.Payload.ElemType = undefined;
25879 if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) {
25880 return Air.Inst.Ref.bool_true;
25881 }
2575025882 try sema.requireRuntimeBlock(block, src, null);
2575125883 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
2575225884 return block.addUnOp(air_tag, operand);
......@@ -25785,6 +25917,11 @@ fn analyzeIsNonErrComptimeOnly(
2578525917 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
2578625918 assert(ot == .ErrorUnion);
2578725919
25920 const payload_ty = operand_ty.errorUnionPayload();
25921 if (payload_ty.zigTypeTag() == .NoReturn) {
25922 return Air.Inst.Ref.bool_false;
25923 }
25924
2578825925 if (Air.refToIndex(operand)) |operand_inst| {
2578925926 switch (sema.air_instructions.items(.tag)[operand_inst]) {
2579025927 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
......@@ -27922,6 +28059,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2792228059 };
2792328060 return sema.failWithOwnedErrorMsg(msg);
2792428061 }
28062 if (field_ty.zigTypeTag() == .NoReturn) {
28063 const msg = msg: {
28064 const tree = try sema.getAstTree(&block_scope);
28065 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i);
28066 const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{});
28067 errdefer msg.destroy(sema.gpa);
28068
28069 try sema.addDeclaredHereNote(msg, field_ty);
28070 break :msg msg;
28071 };
28072 return sema.failWithOwnedErrorMsg(msg);
28073 }
2792528074 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
2792628075 const msg = msg: {
2792728076 const tree = try sema.getAstTree(&block_scope);
......@@ -28028,10 +28177,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2802828177 extra_index = decls_it.extra_index;
2802928178
2803028179 const body = zir.extra[extra_index..][0..body_len];
28031 if (fields_len == 0) {
28032 assert(body.len == 0);
28033 return;
28034 }
2803528180 extra_index += body.len;
2803628181
2803728182 const decl = mod.declPtr(decl_index);
......@@ -28119,6 +28264,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2811928264 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
2812028265 }
2812128266
28267 if (fields_len == 0) {
28268 return;
28269 }
28270
2812228271 const bits_per_field = 4;
2812328272 const fields_per_u32 = 32 / bits_per_field;
2812428273 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
......@@ -28654,7 +28803,9 @@ pub fn typeHasOnePossibleValue(
2865428803 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
2865528804 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
2865628805 return null;
28657 const only_field = union_obj.fields.values()[0];
28806 const fields = union_obj.fields.values();
28807 if (fields.len == 0) return Value.initTag(.empty_struct_value);
28808 const only_field = fields[0];
2865828809 if (only_field.ty.eql(resolved_ty, sema.mod)) {
2865928810 const msg = try Module.ErrorMsg.create(
2866028811 sema.gpa,
......@@ -28733,6 +28884,16 @@ fn enumFieldSrcLoc(
2873328884 .container_decl_arg_trailing,
2873428885 => tree.containerDeclArg(enum_node),
2873528886
28887 .tagged_union,
28888 .tagged_union_trailing,
28889 => tree.taggedUnion(enum_node),
28890 .tagged_union_two,
28891 .tagged_union_two_trailing,
28892 => tree.taggedUnionTwo(&buffer, enum_node),
28893 .tagged_union_enum_tag,
28894 .tagged_union_enum_tag_trailing,
28895 => tree.taggedUnionEnumTag(enum_node),
28896
2873628897 // Container was constructed with `@Type`.
2873728898 else => return LazySrcLoc.nodeOffset(0),
2873828899 };
......@@ -29383,7 +29544,9 @@ fn unionFieldAlignment(
2938329544 src: LazySrcLoc,
2938429545 field: Module.Union.Field,
2938529546) !u32 {
29386 if (field.abi_align == 0) {
29547 if (field.ty.zigTypeTag() == .NoReturn) {
29548 return @as(u32, 0);
29549 } else if (field.abi_align == 0) {
2938729550 return sema.typeAbiAlignment(block, src, field.ty);
2938829551 } else {
2938929552 return field.abi_align;
src/print_zir.zig+10-5
......@@ -1443,7 +1443,7 @@ const Writer = struct {
14431443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
14441444
14451445 if (decls_len == 0) {
1446 try stream.writeAll("{}, ");
1446 try stream.writeAll("{}");
14471447 } else {
14481448 const prev_parent_decl_node = self.parent_decl_node;
14491449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
......@@ -1454,15 +1454,20 @@ const Writer = struct {
14541454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
14551455 self.indent -= 2;
14561456 try stream.writeByteNTimes(' ', self.indent);
1457 try stream.writeAll("}, ");
1457 try stream.writeAll("}");
14581458 }
14591459
1460 assert(fields_len != 0);
1461
14621460 if (tag_type_ref != .none) {
1463 try self.writeInstRef(stream, tag_type_ref);
14641461 try stream.writeAll(", ");
1462 try self.writeInstRef(stream, tag_type_ref);
1463 }
1464
1465 if (fields_len == 0) {
1466 try stream.writeAll("})");
1467 try self.writeSrcNode(stream, src_node);
1468 return;
14651469 }
1470 try stream.writeAll(", ");
14661471
14671472 const body = self.code.extra[extra_index..][0..body_len];
14681473 extra_index += body.len;
src/type.zig+4-1
......@@ -2488,7 +2488,7 @@ pub const Type = extern union {
24882488 },
24892489 .union_safety_tagged, .union_tagged => {
24902490 const union_obj = ty.cast(Payload.Union).?.data;
2491 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
2491 if (union_obj.fields.count() > 0 and try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
24922492 return true;
24932493 }
24942494 if (sema_kit) |sk| {
......@@ -3113,6 +3113,9 @@ pub const Type = extern union {
31133113 .sema_kit => unreachable, // handled above
31143114 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
31153115 };
3116 if (union_obj.fields.count() == 0) {
3117 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };
3118 }
31163119
31173120 var max_align: u32 = 0;
31183121 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
test/behavior.zig+1
......@@ -167,6 +167,7 @@ test {
167167 if (builtin.zig_backend != .stage1) {
168168 _ = @import("behavior/decltest.zig");
169169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
170 _ = @import("behavior/empty_union.zig");
170171 }
171172
172173 if (builtin.os.tag != .wasi) {
test/behavior/empty_union.zig created+54
......@@ -0,0 +1,54 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "switch on empty enum" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8
9 const E = enum {};
10 var e: E = undefined;
11 switch (e) {}
12}
13
14test "switch on empty enum with a specified tag type" {
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17
18 const E = enum(u8) {};
19 var e: E = undefined;
20 switch (e) {}
21}
22
23test "switch on empty auto numbered tagged union" {
24 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27
28 const U = union(enum(u8)) {};
29 var u: U = undefined;
30 switch (u) {}
31}
32
33test "switch on empty tagged union" {
34 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
37
38 const E = enum {};
39 const U = union(E) {};
40 var u: U = undefined;
41 switch (u) {}
42}
43
44test "empty union" {
45 const U = union {};
46 try expect(@sizeOf(U) == 0);
47 try expect(@alignOf(U) == 0);
48}
49
50test "empty extern union" {
51 const U = extern union {};
52 try expect(@sizeOf(U) == 0);
53 try expect(@alignOf(U) == 1);
54}
test/behavior/error.zig+61-1
......@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725725 try expect(value == 255);
726726}
727727
728test {
728test "pointer to error union payload" {
729729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -736,3 +736,63 @@ test {
736736 const payload_ptr = &(err_union catch unreachable);
737737 try expect(payload_ptr.* == 15);
738738}
739
740const NoReturn = struct {
741 var a: u32 = undefined;
742 fn someData() bool {
743 a -= 1;
744 return a == 0;
745 }
746 fn loop() !noreturn {
747 while (true) {
748 if (someData())
749 return error.GenericFailure;
750 }
751 }
752 fn testTry() anyerror {
753 try loop();
754 }
755 fn testCatch() anyerror {
756 loop() catch return error.OtherFailure;
757 @compileError("bad");
758 }
759};
760
761test "error union of noreturn used with if" {
762 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
767
768 NoReturn.a = 64;
769 if (NoReturn.loop()) {
770 @compileError("bad");
771 } else |err| {
772 try expect(err == error.GenericFailure);
773 }
774}
775
776test "error union of noreturn used with try" {
777 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
778 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
782
783 NoReturn.a = 64;
784 const err = NoReturn.testTry();
785 try expect(err == error.GenericFailure);
786}
787
788test "error union of noreturn used with catch" {
789 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
793 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
794
795 NoReturn.a = 64;
796 const err = NoReturn.testCatch();
797 try expect(err == error.OtherFailure);
798}
test/behavior/optional.zig+36
......@@ -369,3 +369,39 @@ test "optional pointer to zero bit error union payload" {
369369 some.foo();
370370 } else |_| {}
371371}
372
373const NoReturn = struct {
374 var a: u32 = undefined;
375 fn someData() bool {
376 a -= 1;
377 return a == 0;
378 }
379 fn loop() ?noreturn {
380 while (true) {
381 if (someData()) return null;
382 }
383 }
384 fn testOrelse() u32 {
385 loop() orelse return 123;
386 @compileError("bad");
387 }
388};
389
390test "optional of noreturn used with if" {
391 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
392
393 NoReturn.a = 64;
394 if (NoReturn.loop()) |_| {
395 @compileError("bad");
396 } else {
397 try expect(true);
398 }
399}
400
401test "optional of noreturn used with orelse" {
402 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
403
404 NoReturn.a = 64;
405 const val = NoReturn.testOrelse();
406 try expect(val == 123);
407}
test/behavior/union.zig+45
......@@ -1256,3 +1256,48 @@ test "return an extern union from C calling convention" {
12561256 });
12571257 try expect(u.d == 4.0);
12581258}
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/enum_with_0_fields.zig deleted-7
......@@ -1,7 +0,0 @@
1const Foo = enum {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: enum declarations must have at least one tag
test/cases/compile_errors/invalid_error_union_payload_type.zig created+13
......@@ -0,0 +1,13 @@
1comptime {
2 _ = anyerror!anyopaque;
3}
4comptime {
5 _ = anyerror!anyerror;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:18: error: error union with payload of opaque type 'anyopaque' not allowed
13// :5:18: error: error union with payload of error set type 'anyerror' not allowed
test/cases/compile_errors/invalid_optional_payload_type.zig created+13
......@@ -0,0 +1,13 @@
1comptime {
2 _ = ?anyopaque;
3}
4comptime {
5 _ = ?@TypeOf(null);
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:10: error: opaque type 'anyopaque' cannot be optional
13// :5:10: error: type '@TypeOf(null)' cannot be optional
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/reify_type_for_exhaustive_enum_with_zero_fields.zig deleted-18
......@@ -1,18 +0,0 @@
1const Tag = @Type(.{
2 .Enum = .{
3 .layout = .Auto,
4 .tag_type = u1,
5 .fields = &.{},
6 .decls = &.{},
7 .is_exhaustive = true,
8 },
9});
10export fn entry() void {
11 _ = @intToEnum(Tag, 0);
12}
13
14// error
15// backend=stage2
16// target=native
17//
18// :1:13: error: enums must have at least one field
test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig deleted-17
......@@ -1,17 +0,0 @@
1const Untagged = @Type(.{
2 .Union = .{
3 .layout = .Auto,
4 .tag_type = null,
5 .fields = &.{},
6 .decls = &.{},
7 },
8});
9export fn entry() void {
10 _ = Untagged{};
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :1:18: error: unions must have at least one field
test/cases/compile_errors/runtime_cast_to_union_which_has_non-void_fields.zig-2
......@@ -18,6 +18,4 @@ fn foo(l: Letter) void {
1818//
1919// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields
2020// :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'
2321// :2:15: note: union declared here
test/cases/compile_errors/union_fields_with_value_assignments.zig deleted-7
......@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
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
test/cases/compile_errors/union_with_0_fields.zig deleted-7
......@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
test/cases/compile_errors/using_invalid_types_in_function_call_raises_an_error.zig deleted-11
......@@ -1,11 +0,0 @@
1const MenuEffect = enum {};
2fn func(effect: MenuEffect) void { _ = effect; }
3export fn entry() void {
4 func(MenuEffect.ThisDoesNotExist);
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :1:20: error: enum declarations must have at least one tag
test/stage2/cbe.zig-9
......@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {
704704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
705705 });
706706
707 case.addError(
708 \\const E1 = enum {};
709 \\export fn foo() void {
710 \\ _ = E1.a;
711 \\}
712 , &.{
713 ":1:12: error: enum declarations must have at least one tag",
714 });
715
716707 case.addError(
717708 \\const E1 = enum { a, b, _ };
718709 \\export fn foo() void {