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(...@@ -4557,9 +4557,6 @@ fn unionDeclInner(
4557 wip_members.appendToField(@enumToInt(tag_value));4557 wip_members.appendToField(@enumToInt(tag_value));
4558 }4558 }
4559 }4559 }
4560 if (field_count == 0) {
4561 return astgen.failNode(node, "union declarations must have at least one tag", .{});
4562 }
45634560
4564 if (!block_scope.isEmpty()) {4561 if (!block_scope.isEmpty()) {
4565 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4562 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
...@@ -4715,12 +4712,6 @@ fn containerDecl(...@@ -4715,12 +4712,6 @@ fn containerDecl(
4715 .nonexhaustive_node = nonexhaustive_node,4712 .nonexhaustive_node = nonexhaustive_node,
4716 };4713 };
4717 };4714 };
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 }
4724 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {4715 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
4725 try astgen.appendErrorNodeNotes(4716 try astgen.appendErrorNodeNotes(
4726 node,4717 node,
src/Sema.zig+281-118
...@@ -3773,6 +3773,7 @@ fn validateStructInit(...@@ -3773,6 +3773,7 @@ fn validateStructInit(
3773 }3773 }
37743774
3775 var root_msg: ?*Module.ErrorMsg = null;3775 var root_msg: ?*Module.ErrorMsg = null;
3776 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
37763777
3777 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);3778 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
3778 if ((is_comptime or block.is_comptime) and3779 if ((is_comptime or block.is_comptime) and
...@@ -3948,6 +3949,7 @@ fn validateStructInit(...@@ -3948,6 +3949,7 @@ fn validateStructInit(
3948 }3949 }
39493950
3950 if (root_msg) |msg| {3951 if (root_msg) |msg| {
3952 root_msg = null;
3951 if (struct_ty.castTag(.@"struct")) |struct_obj| {3953 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3952 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);3954 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
3953 defer gpa.free(fqn);3955 defer gpa.free(fqn);
...@@ -4006,6 +4008,8 @@ fn zirValidateArrayInit(...@@ -4006,6 +4008,8 @@ fn zirValidateArrayInit(
4006 if (instrs.len != array_len and array_ty.isTuple()) {4008 if (instrs.len != array_len and array_ty.isTuple()) {
4007 const struct_obj = array_ty.castTag(.tuple).?.data;4009 const struct_obj = array_ty.castTag(.tuple).?.data;
4008 var root_msg: ?*Module.ErrorMsg = null;4010 var root_msg: ?*Module.ErrorMsg = null;
4011 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
4012
4009 for (struct_obj.values) |default_val, i| {4013 for (struct_obj.values) |default_val, i| {
4010 if (i < instrs.len) continue;4014 if (i < instrs.len) continue;
40114015
...@@ -4020,6 +4024,7 @@ fn zirValidateArrayInit(...@@ -4020,6 +4024,7 @@ fn zirValidateArrayInit(
4020 }4024 }
40214025
4022 if (root_msg) |msg| {4026 if (root_msg) |msg| {
4027 root_msg = null;
4023 return sema.failWithOwnedErrorMsg(msg);4028 return sema.failWithOwnedErrorMsg(msg);
4024 }4029 }
4025 }4030 }
...@@ -6702,8 +6707,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -6702,8 +6707,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
6702 defer tracy.end();6707 defer tracy.end();
67036708
6704 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6709 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6705 const src = inst_data.src();6710 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
6706 const child_type = try sema.resolveType(block, src, inst_data.operand);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 }
6707 const opt_type = try Type.optional(sema.arena, child_type);6717 const opt_type = try Type.optional(sema.arena, child_type);
67086718
6709 return sema.addType(opt_type);6719 return sema.addType(opt_type);
...@@ -6802,6 +6812,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6802,6 +6812,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
6802 error_set.fmt(sema.mod),6812 error_set.fmt(sema.mod),
6803 });6813 });
6804 }6814 }
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 }
6805 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);6824 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
6806 return sema.addType(err_union_ty);6825 return sema.addType(err_union_ty);
6807}6826}
...@@ -8968,12 +8987,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8968,12 +8987,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8968 },8987 },
8969 };8988 };
89708989
8971 const union_originally = blk: {8990 const maybe_union_ty = blk: {
8972 const zir_data = sema.code.instructions.items(.data);8991 const zir_data = sema.code.instructions.items(.data);
8973 const cond_index = Zir.refToIndex(extra.data.operand).?;8992 const cond_index = Zir.refToIndex(extra.data.operand).?;
8974 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;8993 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);
8976 };8995 };
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
8978 const operand_ty = sema.typeOf(operand);9002 const operand_ty = sema.typeOf(operand);
89799003
...@@ -9008,7 +9032,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9008,7 +9032,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9008 .Union => unreachable, // handled in zirSwitchCond9032 .Union => unreachable, // handled in zirSwitchCond
9009 .Enum => {9033 .Enum => {
9010 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());9034 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;
9012 mem.set(?Module.SwitchProngSrc, seen_fields, null);9038 mem.set(?Module.SwitchProngSrc, seen_fields, null);
90139039
9014 // This is used for non-exhaustive enum values that do not correspond to any tags.9040 // 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...@@ -9602,6 +9628,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9602 }9628 }
96039629
9604 if (scalar_cases_len + multi_cases_len == 0) {9630 if (scalar_cases_len + multi_cases_len == 0) {
9631 if (empty_enum) {
9632 return Air.Inst.Ref.void_value;
9633 }
9605 if (special_prong == .none) {9634 if (special_prong == .none) {
9606 return sema.fail(block, src, "switch must handle all possibilities", .{});9635 return sema.fail(block, src, "switch must handle all possibilities", .{});
9607 }9636 }
...@@ -9641,18 +9670,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9641,18 +9670,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9641 const item = try sema.resolveInst(item_ref);9670 const item = try sema.resolveInst(item_ref);
9642 // `item` is already guaranteed to be constant known.9671 // `item` is already guaranteed to be constant known.
96439672
9644 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9673 const analyze_body = if (union_originally) blk: {
9645 error.ComptimeBreak => {9674 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9646 const zir_datas = sema.code.instructions.items(.data);9675 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9647 const break_data = zir_datas[sema.comptime_break_inst].@"break";9676 break :blk field_ty.zigTypeTag() != .NoReturn;
9648 try sema.addRuntimeBreak(&case_block, .{9677 } else true;
9649 .block_inst = break_data.block_inst,9678
9650 .operand = break_data.operand,9679 if (analyze_body) {
9651 .inst = sema.comptime_break_inst,9680 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9652 });9681 error.ComptimeBreak => {
9653 },9682 const zir_datas = sema.code.instructions.items(.data);
9654 else => |e| return e,9683 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9655 };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
9657 try wip_captures.finalize();9696 try wip_captures.finalize();
96589697
...@@ -9693,20 +9732,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9693,20 +9732,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9693 if (ranges_len == 0) {9732 if (ranges_len == 0) {
9694 cases_len += 1;9733 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
9696 const body = sema.code.extra[extra_index..][0..body_len];9745 const body = sema.code.extra[extra_index..][0..body_len];
9697 extra_index += body_len;9746 extra_index += body_len;
9698 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9747 if (analyze_body) {
9699 error.ComptimeBreak => {9748 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9700 const zir_datas = sema.code.instructions.items(.data);9749 error.ComptimeBreak => {
9701 const break_data = zir_datas[sema.comptime_break_inst].@"break";9750 const zir_datas = sema.code.instructions.items(.data);
9702 try sema.addRuntimeBreak(&case_block, .{9751 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9703 .block_inst = break_data.block_inst,9752 try sema.addRuntimeBreak(&case_block, .{
9704 .operand = break_data.operand,9753 .block_inst = break_data.block_inst,
9705 .inst = sema.comptime_break_inst,9754 .operand = break_data.operand,
9706 });9755 .inst = sema.comptime_break_inst,
9707 },9756 });
9708 else => |e| return e,9757 },
9709 };9758 else => |e| return e,
9759 };
9760 } else {
9761 _ = try case_block.addNoOp(.unreach);
9762 }
97109763
9711 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +9764 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
9712 case_block.instructions.items.len);9765 case_block.instructions.items.len);
...@@ -9828,7 +9881,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9828,7 +9881,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9828 case_block.instructions.shrinkRetainingCapacity(0);9881 case_block.instructions.shrinkRetainingCapacity(0);
9829 case_block.wip_capture_scope = wip_captures.scope;9882 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) {
9832 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {9895 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
9833 error.ComptimeBreak => {9896 error.ComptimeBreak => {
9834 const zir_datas = sema.code.instructions.items(.data);9897 const zir_datas = sema.code.instructions.items(.data);
...@@ -13244,6 +13307,14 @@ fn analyzeCmpUnionTag(...@@ -13244,6 +13307,14 @@ fn analyzeCmpUnionTag(
13244 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);13307 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
13245 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);13308 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
13247 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);13318 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
13248}13319}
1324913320
...@@ -15598,6 +15669,8 @@ fn finishStructInit(...@@ -15598,6 +15669,8 @@ fn finishStructInit(
15598 const gpa = sema.gpa;15669 const gpa = sema.gpa;
1559915670
15600 var root_msg: ?*Module.ErrorMsg = null;15671 var root_msg: ?*Module.ErrorMsg = null;
15672 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
15673
15601 if (struct_ty.isAnonStruct()) {15674 if (struct_ty.isAnonStruct()) {
15602 const struct_obj = struct_ty.castTag(.anon_struct).?.data;15675 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
15603 for (struct_obj.values) |default_val, i| {15676 for (struct_obj.values) |default_val, i| {
...@@ -15653,6 +15726,7 @@ fn finishStructInit(...@@ -15653,6 +15726,7 @@ fn finishStructInit(
15653 }15726 }
1565415727
15655 if (root_msg) |msg| {15728 if (root_msg) |msg| {
15729 root_msg = null;
15656 if (struct_ty.castTag(.@"struct")) |struct_obj| {15730 if (struct_ty.castTag(.@"struct")) |struct_obj| {
15657 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);15731 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
15658 defer gpa.free(fqn);15732 defer gpa.free(fqn);
...@@ -16655,43 +16729,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -16655,43 +16729,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1665516729
16656 // Fields16730 // Fields
16657 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));16731 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
16658 if (fields_len > 0) {16732 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16659 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);16733 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16660 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{16734 .ty = enum_obj.tag_ty,
16661 .ty = enum_obj.tag_ty,16735 .mod = mod,
16662 .mod = mod,16736 });
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 );
1668016737
16681 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);16738 var i: usize = 0;
16682 if (gop.found_existing) {16739 while (i < fields_len) : (i += 1) {
16683 // TODO: better source location16740 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16684 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});16741 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16685 }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);16754 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16688 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{16755 if (gop.found_existing) {
16689 .ty = enum_obj.tag_ty,16756 // TODO: better source location
16690 .mod = mod,16757 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
16691 });
16692 }16758 }
16693 } else {16759
16694 return sema.fail(block, src, "enums must have at least one field", .{});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 });
16695 }16765 }
1669616766
16697 try new_decl.finalizeNewArena(&new_decl_arena);16767 try new_decl.finalizeNewArena(&new_decl_arena);
...@@ -16816,58 +16886,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -16816,58 +16886,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
16816 }16886 }
1681716887
16818 // Fields16888 // Fields
16819 if (fields_len > 0) {16889 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16820 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1682116890
16822 var i: usize = 0;16891 var i: usize = 0;
16823 while (i < fields_len) : (i += 1) {16892 while (i < fields_len) : (i += 1) {
16824 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);16893 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16825 const field_struct_val = elem_val.castTag(.aggregate).?.data;16894 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16826 // TODO use reflection instead of magic numbers here16895 // TODO use reflection instead of magic numbers here
16827 // name: []const u816896 // name: []const u8
16828 const name_val = field_struct_val[0];16897 const name_val = field_struct_val[0];
16829 // field_type: type,16898 // field_type: type,
16830 const field_type_val = field_struct_val[1];16899 const field_type_val = field_struct_val[1];
16831 // alignment: comptime_int,16900 // alignment: comptime_int,
16832 const alignment_val = field_struct_val[2];16901 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 );
1683916902
16840 if (enum_field_names) |set| {16903 const field_name = try name_val.toAllocatedBytes(
16841 set.putAssumeCapacity(field_name, {});16904 Type.initTag(.const_slice_u8),
16842 }16905 new_decl_arena_allocator,
16906 sema.mod,
16907 );
1684316908
16844 if (tag_ty_field_names) |*names| {16909 if (enum_field_names) |set| {
16845 const enum_has_field = names.orderedRemove(field_name);16910 set.putAssumeCapacity(field_name, {});
16846 if (!enum_has_field) {16911 }
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 }
1685616912
16857 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);16913 if (tag_ty_field_names) |*names| {
16858 if (gop.found_existing) {16914 const enum_has_field = names.orderedRemove(field_name);
16859 // TODO: better source location16915 if (!enum_has_field) {
16860 return sema.fail(block, src, "duplicate union field {s}", .{field_name});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);
16861 }16923 }
16924 }
1686216925
16863 var buffer: Value.ToTypeBuffer = undefined;16926 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16864 gop.value_ptr.* = .{16927 if (gop.found_existing) {
16865 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),16928 // TODO: better source location
16866 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),16929 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
16867 };
16868 }16930 }
16869 } else {16931
16870 return sema.fail(block, src, "unions must have at least one field", .{});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 };
16871 }16937 }
1687216938
16873 if (tag_ty_field_names) |names| {16939 if (tag_ty_field_names) |names| {
...@@ -21701,6 +21767,18 @@ fn unionFieldPtr(...@@ -21701,6 +21767,18 @@ fn unionFieldPtr(
21701 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),21767 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
21702 });21768 });
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
21704 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {21782 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
21705 switch (union_obj.layout) {21783 switch (union_obj.layout) {
21706 .Auto => if (!initializing) {21784 .Auto => if (!initializing) {
...@@ -21753,6 +21831,10 @@ fn unionFieldPtr(...@@ -21753,6 +21831,10 @@ fn unionFieldPtr(
21753 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21831 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21754 try sema.addSafetyCheck(block, ok, .inactive_union_field);21832 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21755 }21833 }
21834 if (field.ty.zigTypeTag() == .NoReturn) {
21835 _ = try block.addNoOp(.unreach);
21836 return Air.Inst.Ref.unreachable_value;
21837 }
21756 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);21838 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
21757}21839}
2175821840
...@@ -21821,6 +21903,10 @@ fn unionFieldVal(...@@ -21821,6 +21903,10 @@ fn unionFieldVal(
21821 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21903 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21822 try sema.addSafetyCheck(block, ok, .inactive_union_field);21904 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21823 }21905 }
21906 if (field.ty.zigTypeTag() == .NoReturn) {
21907 _ = try block.addNoOp(.unreach);
21908 return Air.Inst.Ref.unreachable_value;
21909 }
21824 return block.addStructFieldVal(union_byval, field_index, field.ty);21910 return block.addStructFieldVal(union_byval, field_index, field.ty);
21825}21911}
2182621912
...@@ -25021,6 +25107,18 @@ fn coerceEnumToUnion(...@@ -25021,6 +25107,18 @@ fn coerceEnumToUnion(
25021 };25107 };
25022 const field = union_obj.fields.values()[field_index];25108 const field = union_obj.fields.values()[field_index];
25023 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);25109 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 }
25024 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {25122 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
25025 const msg = msg: {25123 const msg = msg: {
25026 const field_name = union_obj.fields.keys()[field_index];25124 const field_name = union_obj.fields.keys()[field_index];
...@@ -25056,13 +25154,37 @@ fn coerceEnumToUnion(...@@ -25056,13 +25154,37 @@ fn coerceEnumToUnion(
25056 return sema.failWithOwnedErrorMsg(msg);25154 return sema.failWithOwnedErrorMsg(msg);
25057 }25155 }
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
25059 // If the union has all fields 0 bits, the union value is just the enum value.25182 // If the union has all fields 0 bits, the union value is just the enum value.
25060 if (union_ty.unionHasAllZeroBitFieldTypes()) {25183 if (union_ty.unionHasAllZeroBitFieldTypes()) {
25061 return block.addBitCast(union_ty, enum_tag);25184 return block.addBitCast(union_ty, enum_tag);
25062 }25185 }
2506325186
25064 const msg = msg: {25187 const msg = msg: {
25065 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
25066 const msg = try sema.errMsg(25188 const msg = try sema.errMsg(
25067 block,25189 block,
25068 inst_src,25190 inst_src,
...@@ -25073,11 +25195,11 @@ fn coerceEnumToUnion(...@@ -25073,11 +25195,11 @@ fn coerceEnumToUnion(
2507325195
25074 var it = union_obj.fields.iterator();25196 var it = union_obj.fields.iterator();
25075 var field_index: usize = 0;25197 var field_index: usize = 0;
25076 while (it.next()) |field| {25198 while (it.next()) |field| : (field_index += 1) {
25077 const field_name = field.key_ptr.*;25199 const field_name = field.key_ptr.*;
25078 const field_ty = field.value_ptr.ty;25200 const field_ty = field.value_ptr.ty;
25201 if (!field_ty.hasRuntimeBits()) continue;
25079 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });25202 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
25080 field_index += 1;
25081 }25203 }
25082 try sema.addDeclaredHereNote(msg, union_ty);25204 try sema.addDeclaredHereNote(msg, union_ty);
25083 break :msg msg;25205 break :msg msg;
...@@ -25380,6 +25502,7 @@ fn coerceTupleToStruct(...@@ -25380,6 +25502,7 @@ fn coerceTupleToStruct(
2538025502
25381 // Populate default field values and report errors for missing fields.25503 // Populate default field values and report errors for missing fields.
25382 var root_msg: ?*Module.ErrorMsg = null;25504 var root_msg: ?*Module.ErrorMsg = null;
25505 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2538325506
25384 for (field_refs) |*field_ref, i| {25507 for (field_refs) |*field_ref, i| {
25385 if (field_ref.* != .none) continue;25508 if (field_ref.* != .none) continue;
...@@ -25405,6 +25528,7 @@ fn coerceTupleToStruct(...@@ -25405,6 +25528,7 @@ fn coerceTupleToStruct(
25405 }25528 }
2540625529
25407 if (root_msg) |msg| {25530 if (root_msg) |msg| {
25531 root_msg = null;
25408 try sema.addDeclaredHereNote(msg, struct_ty);25532 try sema.addDeclaredHereNote(msg, struct_ty);
25409 return sema.failWithOwnedErrorMsg(msg);25533 return sema.failWithOwnedErrorMsg(msg);
25410 }25534 }
...@@ -25474,6 +25598,7 @@ fn coerceTupleToTuple(...@@ -25474,6 +25598,7 @@ fn coerceTupleToTuple(
2547425598
25475 // Populate default field values and report errors for missing fields.25599 // Populate default field values and report errors for missing fields.
25476 var root_msg: ?*Module.ErrorMsg = null;25600 var root_msg: ?*Module.ErrorMsg = null;
25601 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2547725602
25478 for (field_refs) |*field_ref, i| {25603 for (field_refs) |*field_ref, i| {
25479 if (field_ref.* != .none) continue;25604 if (field_ref.* != .none) continue;
...@@ -25509,6 +25634,7 @@ fn coerceTupleToTuple(...@@ -25509,6 +25634,7 @@ fn coerceTupleToTuple(
25509 }25634 }
2551025635
25511 if (root_msg) |msg| {25636 if (root_msg) |msg| {
25637 root_msg = null;
25512 try sema.addDeclaredHereNote(msg, tuple_ty);25638 try sema.addDeclaredHereNote(msg, tuple_ty);
25513 return sema.failWithOwnedErrorMsg(msg);25639 return sema.failWithOwnedErrorMsg(msg);
25514 }25640 }
...@@ -25747,6 +25873,12 @@ fn analyzeIsNull(...@@ -25747,6 +25873,12 @@ fn analyzeIsNull(
25747 return Air.Inst.Ref.bool_false;25873 return Air.Inst.Ref.bool_false;
25748 }25874 }
25749 }25875 }
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 }
25750 try sema.requireRuntimeBlock(block, src, null);25882 try sema.requireRuntimeBlock(block, src, null);
25751 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;25883 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
25752 return block.addUnOp(air_tag, operand);25884 return block.addUnOp(air_tag, operand);
...@@ -25785,6 +25917,11 @@ fn analyzeIsNonErrComptimeOnly(...@@ -25785,6 +25917,11 @@ fn analyzeIsNonErrComptimeOnly(
25785 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;25917 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
25786 assert(ot == .ErrorUnion);25918 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
25788 if (Air.refToIndex(operand)) |operand_inst| {25925 if (Air.refToIndex(operand)) |operand_inst| {
25789 switch (sema.air_instructions.items(.tag)[operand_inst]) {25926 switch (sema.air_instructions.items(.tag)[operand_inst]) {
25790 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,25927 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
...@@ -27922,6 +28059,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27922,6 +28059,18 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27922 };28059 };
27923 return sema.failWithOwnedErrorMsg(msg);28060 return sema.failWithOwnedErrorMsg(msg);
27924 }28061 }
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 }
27925 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {28074 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
27926 const msg = msg: {28075 const msg = msg: {
27927 const tree = try sema.getAstTree(&block_scope);28076 const tree = try sema.getAstTree(&block_scope);
...@@ -28028,10 +28177,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -28028,10 +28177,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
28028 extra_index = decls_it.extra_index;28177 extra_index = decls_it.extra_index;
2802928178
28030 const body = zir.extra[extra_index..][0..body_len];28179 const body = zir.extra[extra_index..][0..body_len];
28031 if (fields_len == 0) {
28032 assert(body.len == 0);
28033 return;
28034 }
28035 extra_index += body.len;28180 extra_index += body.len;
2803628181
28037 const decl = mod.declPtr(decl_index);28182 const decl = mod.declPtr(decl_index);
...@@ -28119,6 +28264,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -28119,6 +28264,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
28119 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;28264 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
28120 }28265 }
2812128266
28267 if (fields_len == 0) {
28268 return;
28269 }
28270
28122 const bits_per_field = 4;28271 const bits_per_field = 4;
28123 const fields_per_u32 = 32 / bits_per_field;28272 const fields_per_u32 = 32 / bits_per_field;
28124 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;28273 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -28654,7 +28803,9 @@ pub fn typeHasOnePossibleValue(...@@ -28654,7 +28803,9 @@ pub fn typeHasOnePossibleValue(
28654 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;28803 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
28655 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse28804 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
28656 return null;28805 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];
28658 if (only_field.ty.eql(resolved_ty, sema.mod)) {28809 if (only_field.ty.eql(resolved_ty, sema.mod)) {
28659 const msg = try Module.ErrorMsg.create(28810 const msg = try Module.ErrorMsg.create(
28660 sema.gpa,28811 sema.gpa,
...@@ -28733,6 +28884,16 @@ fn enumFieldSrcLoc(...@@ -28733,6 +28884,16 @@ fn enumFieldSrcLoc(
28733 .container_decl_arg_trailing,28884 .container_decl_arg_trailing,
28734 => tree.containerDeclArg(enum_node),28885 => 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
28736 // Container was constructed with `@Type`.28897 // Container was constructed with `@Type`.
28737 else => return LazySrcLoc.nodeOffset(0),28898 else => return LazySrcLoc.nodeOffset(0),
28738 };28899 };
...@@ -29383,7 +29544,9 @@ fn unionFieldAlignment(...@@ -29383,7 +29544,9 @@ fn unionFieldAlignment(
29383 src: LazySrcLoc,29544 src: LazySrcLoc,
29384 field: Module.Union.Field,29545 field: Module.Union.Field,
29385) !u32 {29546) !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) {
29387 return sema.typeAbiAlignment(block, src, field.ty);29550 return sema.typeAbiAlignment(block, src, field.ty);
29388 } else {29551 } else {
29389 return field.abi_align;29552 return field.abi_align;
src/print_zir.zig+10-5
...@@ -1443,7 +1443,7 @@ const Writer = struct {...@@ -1443,7 +1443,7 @@ const Writer = struct {
1443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
14441444
1445 if (decls_len == 0) {1445 if (decls_len == 0) {
1446 try stream.writeAll("{}, ");1446 try stream.writeAll("{}");
1447 } else {1447 } else {
1448 const prev_parent_decl_node = self.parent_decl_node;1448 const prev_parent_decl_node = self.parent_decl_node;
1449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);1449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
...@@ -1454,15 +1454,20 @@ const Writer = struct {...@@ -1454,15 +1454,20 @@ const Writer = struct {
1454 extra_index = try self.writeDecls(stream, decls_len, extra_index);1454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1455 self.indent -= 2;1455 self.indent -= 2;
1456 try stream.writeByteNTimes(' ', self.indent);1456 try stream.writeByteNTimes(' ', self.indent);
1457 try stream.writeAll("}, ");1457 try stream.writeAll("}");
1458 }1458 }
14591459
1460 assert(fields_len != 0);
1461
1462 if (tag_type_ref != .none) {1460 if (tag_type_ref != .none) {
1463 try self.writeInstRef(stream, tag_type_ref);
1464 try stream.writeAll(", ");1461 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;
1465 }1469 }
1470 try stream.writeAll(", ");
14661471
1467 const body = self.code.extra[extra_index..][0..body_len];1472 const body = self.code.extra[extra_index..][0..body_len];
1468 extra_index += body.len;1473 extra_index += body.len;
src/type.zig+4-1
...@@ -2488,7 +2488,7 @@ pub const Type = extern union {...@@ -2488,7 +2488,7 @@ pub const Type = extern union {
2488 },2488 },
2489 .union_safety_tagged, .union_tagged => {2489 .union_safety_tagged, .union_tagged => {
2490 const union_obj = ty.cast(Payload.Union).?.data;2490 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)) {
2492 return true;2492 return true;
2493 }2493 }
2494 if (sema_kit) |sk| {2494 if (sema_kit) |sk| {
...@@ -3113,6 +3113,9 @@ pub const Type = extern union {...@@ -3113,6 +3113,9 @@ pub const Type = extern union {
3113 .sema_kit => unreachable, // handled above3113 .sema_kit => unreachable, // handled above
3114 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },3114 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
3115 };3115 };
3116 if (union_obj.fields.count() == 0) {
3117 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };
3118 }
31163119
3117 var max_align: u32 = 0;3120 var max_align: u32 = 0;
3118 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);3121 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
test/behavior.zig+1
...@@ -167,6 +167,7 @@ test {...@@ -167,6 +167,7 @@ test {
167 if (builtin.zig_backend != .stage1) {167 if (builtin.zig_backend != .stage1) {
168 _ = @import("behavior/decltest.zig");168 _ = @import("behavior/decltest.zig");
169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
170 _ = @import("behavior/empty_union.zig");
170 }171 }
171172
172 if (builtin.os.tag != .wasi) {173 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" {...@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725 try expect(value == 255);725 try expect(value == 255);
726}726}
727727
728test {728test "pointer to error union payload" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -736,3 +736,63 @@ test {...@@ -736,3 +736,63 @@ test {
736 const payload_ptr = &(err_union catch unreachable);736 const payload_ptr = &(err_union catch unreachable);
737 try expect(payload_ptr.* == 15);737 try expect(payload_ptr.* == 15);
738}738}
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" {...@@ -369,3 +369,39 @@ test "optional pointer to zero bit error union payload" {
369 some.foo();369 some.foo();
370 } else |_| {}370 } else |_| {}
371}371}
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" {...@@ -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/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 {...@@ -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_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 {...@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {
704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
705 });705 });
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
716 case.addError(707 case.addError(
717 \\const E1 = enum { a, b, _ };708 \\const E1 = enum { a, b, _ };
718 \\export fn foo() void {709 \\export fn foo() void {