Skip to content

Commit b0a55e1

Browse files
committed
Sema: make noreturn error union behave correctly
1 parent db0f372 commit b0a55e1

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

src/Sema.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6789,6 +6789,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
67896789
error_set.fmt(sema.mod),
67906790
});
67916791
}
6792+
if (payload.zigTypeTag() == .Opaque) {
6793+
return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
6794+
payload.fmt(sema.mod),
6795+
});
6796+
} else if (payload.zigTypeTag() == .ErrorSet) {
6797+
return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
6798+
payload.fmt(sema.mod),
6799+
});
6800+
}
67926801
const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
67936802
return sema.addType(err_union_ty);
67946803
}
@@ -25763,6 +25772,11 @@ fn analyzeIsNonErrComptimeOnly(
2576325772
if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
2576425773
assert(ot == .ErrorUnion);
2576525774

25775+
const payload_ty = operand_ty.errorUnionPayload();
25776+
if (payload_ty.zigTypeTag() == .NoReturn) {
25777+
return Air.Inst.Ref.bool_false;
25778+
}
25779+
2576625780
if (Air.refToIndex(operand)) |operand_inst| {
2576725781
switch (sema.air_instructions.items(.tag)[operand_inst]) {
2576825782
.wrap_errunion_payload => return Air.Inst.Ref.bool_true,

test/behavior/error.zig

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725725
try expect(value == 255);
726726
}
727727

728-
test {
728+
test "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+
740+
const 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+
761+
test "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+
776+
test "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+
788+
test "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+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
comptime {
2+
_ = anyerror!anyopaque;
3+
}
4+
comptime {
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

0 commit comments

Comments
 (0)