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