Skip to content

Commit 7999374

Browse files
committed
Sema: correct OPV for optional empty error set
prevents crashes in backends; improves codegen; provides more comptime-ness.
1 parent e837765 commit 7999374

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

src/Sema.zig

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9065,10 +9065,14 @@ fn zirOptionalPayload(
90659065
};
90669066

90679067
if (try sema.resolveDefinedValue(block, src, operand)) |val| {
9068-
return if (val.optionalValue(zcu)) |payload|
9069-
Air.internedToRef(payload.toIntern())
9070-
else
9071-
sema.fail(block, src, "unable to unwrap null", .{});
9068+
if (val.optionalValue(zcu)) |payload| return Air.internedToRef(payload.toIntern());
9069+
if (block.isComptime()) return sema.fail(block, src, "unable to unwrap null", .{});
9070+
if (safety_check and block.wantSafety()) {
9071+
try sema.safetyPanic(block, src, .unwrap_null);
9072+
} else {
9073+
_ = try block.addNoOp(.unreach);
9074+
}
9075+
return .unreachable_value;
90729076
}
90739077

90749078
try sema.requireRuntimeBlock(block, src, null);
@@ -36443,7 +36447,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3644336447
.type_int_unsigned, // u0 handled above
3644436448
.type_pointer,
3644536449
.type_slice,
36446-
.type_optional, // ?noreturn handled above
3644736450
.type_anyframe,
3644836451
.type_error_union,
3644936452
.type_anyerror_union,
@@ -36655,6 +36658,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3665536658

3665636659
else => unreachable,
3665736660
},
36661+
36662+
.type_optional => {
36663+
const payload_ip = ip.indexToKey(ty.toIntern()).opt_type;
36664+
// Although ?noreturn is handled above, the element type
36665+
// can be effectively noreturn for example via an empty
36666+
// enum or error set.
36667+
if (ip.isNoReturn(payload_ip)) return try pt.nullValue(ty);
36668+
return null;
36669+
},
3665836670
},
3665936671
};
3666036672
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export fn example() void {
2+
comptime foo() catch |err| switch (err) {};
3+
}
4+
var x: ?error{} = null;
5+
fn foo() !void {
6+
return x.?;
7+
}
8+
// error
9+
// backend=stage2
10+
// target=native
11+
//
12+
// :6:13: error: unable to unwrap null
13+
// :2:17: note: called at comptime here
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const std = @import("std");
2+
3+
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, ra: ?usize) noreturn {
4+
_ = stack_trace;
5+
_ = ra;
6+
if (std.mem.eql(u8, message, "attempt to use null value")) {
7+
std.process.exit(0);
8+
}
9+
std.process.exit(1);
10+
}
11+
12+
pub fn main() !void {
13+
foo() catch |err| switch (err) {};
14+
return error.TestFailed;
15+
}
16+
var x: ?error{} = null;
17+
fn foo() !void {
18+
return x.?;
19+
}
20+
// run
21+
// backend=stage2,llvm
22+
// target=native

0 commit comments

Comments
 (0)