| author | |
| committer | |
| log | 7a39a038dbe99b5189591378eef89ae5c023806d |
| tree | 4581e558c13c8d870577415f4e8ba9cc964ef297 |
| parent | 5f7c7191ab16c4c9320c28652a0d4c4e53af0024 |
4 files changed, 41 insertions(+), 8 deletions(-)
src-self-hosted/Module.zig+2-2| ... | @@ -1345,8 +1345,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1345,8 +1345,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1345 | 1345 | ||
| 1346 | _ = try astgen.blockExpr(self, params_scope, .none, body_block); | 1346 | _ = try astgen.blockExpr(self, params_scope, .none, body_block); |
| 1347 | 1347 | ||
| 1348 | if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or | 1348 | if (gen_scope.instructions.items.len == 0 or |
| 1349 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())) | 1349 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) |
| 1350 | { | 1350 | { |
| 1351 | const src = tree.token_locs[body_block.rbrace].start; | 1351 | const src = tree.token_locs[body_block.rbrace].start; |
| 1352 | _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid); | 1352 | _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid); |
src-self-hosted/zir_sema.zig+20-2| ... | @@ -112,8 +112,17 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -112,8 +112,17 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { | 114 | pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { |
| 115 | for (body.instructions) |src_inst| { | 115 | for (body.instructions) |src_inst, i| { |
| 116 | src_inst.analyzed_inst = try analyzeInst(mod, scope, src_inst); | 116 | const analyzed_inst = try analyzeInst(mod, scope, src_inst); |
| 117 | src_inst.analyzed_inst = analyzed_inst; | ||
| 118 | if (analyzed_inst.ty.zigTypeTag() == .NoReturn) { | ||
| 119 | for (body.instructions[i..]) |unreachable_inst| { | ||
| 120 | if (unreachable_inst.castTag(.dbg_stmt)) |dbg_stmt| { | ||
| 121 | return mod.fail(scope, dbg_stmt.base.src, "unreachable code", .{}); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | break; | ||
| 125 | } | ||
| 117 | } | 126 | } |
| 118 | } | 127 | } |
| 119 | 128 | ||
| ... | @@ -1216,6 +1225,15 @@ fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! | ... | @@ -1216,6 +1225,15 @@ fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! |
| 1216 | 1225 | ||
| 1217 | fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 1226 | fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { |
| 1218 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | 1227 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 1228 | if (b.func) |func| { | ||
| 1229 | // Need to emit a compile error if returning void is not allowed. | ||
| 1230 | const void_inst = try mod.constVoid(scope, inst.base.src); | ||
| 1231 | const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty; | ||
| 1232 | const casted_void = try mod.coerce(scope, fn_ty.fnReturnType(), void_inst); | ||
| 1233 | if (casted_void.ty.zigTypeTag() != .Void) { | ||
| 1234 | return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, casted_void); | ||
| 1235 | } | ||
| 1236 | } | ||
| 1219 | return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid); | 1237 | return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid); |
| 1220 | } | 1238 | } |
| 1221 | 1239 |
test/stage2/cbe.zig+14-4| ... | @@ -10,13 +10,19 @@ const linux_x64 = std.zig.CrossTarget{ | ... | @@ -10,13 +10,19 @@ const linux_x64 = std.zig.CrossTarget{ |
| 10 | 10 | ||
| 11 | pub fn addCases(ctx: *TestContext) !void { | 11 | pub fn addCases(ctx: *TestContext) !void { |
| 12 | ctx.c("empty start function", linux_x64, | 12 | ctx.c("empty start function", linux_x64, |
| 13 | \\export fn _start() noreturn {} | 13 | \\export fn _start() noreturn { |
| 14 | \\ unreachable; | ||
| 15 | \\} | ||
| 14 | , | 16 | , |
| 15 | \\zig_noreturn void _start(void) {} | 17 | \\zig_noreturn void _start(void) { |
| 18 | \\ zig_unreachable(); | ||
| 19 | \\} | ||
| 16 | \\ | 20 | \\ |
| 17 | ); | 21 | ); |
| 18 | ctx.c("less empty start function", linux_x64, | 22 | ctx.c("less empty start function", linux_x64, |
| 19 | \\fn main() noreturn {} | 23 | \\fn main() noreturn { |
| 24 | \\ unreachable; | ||
| 25 | \\} | ||
| 20 | \\ | 26 | \\ |
| 21 | \\export fn _start() noreturn { | 27 | \\export fn _start() noreturn { |
| 22 | \\ main(); | 28 | \\ main(); |
| ... | @@ -28,7 +34,9 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -28,7 +34,9 @@ pub fn addCases(ctx: *TestContext) !void { |
| 28 | \\ main(); | 34 | \\ main(); |
| 29 | \\} | 35 | \\} |
| 30 | \\ | 36 | \\ |
| 31 | \\zig_noreturn void main(void) {} | 37 | \\zig_noreturn void main(void) { |
| 38 | \\ zig_unreachable(); | ||
| 39 | \\} | ||
| 32 | \\ | 40 | \\ |
| 33 | ); | 41 | ); |
| 34 | // TODO: implement return values | 42 | // TODO: implement return values |
| ... | @@ -40,6 +48,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -40,6 +48,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 40 | \\ : [number] "{rax}" (231), | 48 | \\ : [number] "{rax}" (231), |
| 41 | \\ [arg1] "{rdi}" (0) | 49 | \\ [arg1] "{rdi}" (0) |
| 42 | \\ ); | 50 | \\ ); |
| 51 | \\ unreachable; | ||
| 43 | \\} | 52 | \\} |
| 44 | \\ | 53 | \\ |
| 45 | \\export fn _start() noreturn { | 54 | \\export fn _start() noreturn { |
| ... | @@ -62,6 +71,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -62,6 +71,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 62 | \\ register size_t rax_constant __asm__("rax") = 231; | 71 | \\ register size_t rax_constant __asm__("rax") = 231; |
| 63 | \\ register size_t rdi_constant __asm__("rdi") = 0; | 72 | \\ register size_t rdi_constant __asm__("rdi") = 0; |
| 64 | \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant)); | 73 | \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant)); |
| 74 | \\ zig_unreachable(); | ||
| 65 | \\} | 75 | \\} |
| 66 | \\ | 76 | \\ |
| 67 | ); | 77 | ); |
test/stage2/compare_output.zig+5| ... | @@ -26,6 +26,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -26,6 +26,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 26 | 26 | ||
| 27 | case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); | 27 | case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); |
| 28 | 28 | ||
| 29 | case.addError( | ||
| 30 | \\export fn _start() noreturn { | ||
| 31 | \\} | ||
| 32 | , &[_][]const u8{":2:1: error: expected noreturn, found void"}); | ||
| 33 | |||
| 29 | // Regular old hello world | 34 | // Regular old hello world |
| 30 | case.addCompareOutput( | 35 | case.addCompareOutput( |
| 31 | \\export fn _start() noreturn { | 36 | \\export fn _start() noreturn { |