authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-14 13:08:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-14 13:08:55-07:00
log7a39a038dbe99b5189591378eef89ae5c023806d
tree4581e558c13c8d870577415f4e8ba9cc964ef297
parent5f7c7191ab16c4c9320c28652a0d4c4e53af0024

stage2: proper semantic analysis of improper returning of implicit void


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 {
13451345
1346 _ = try astgen.blockExpr(self, params_scope, .none, body_block);1346 _ = try astgen.blockExpr(self, params_scope, .none, body_block);
13471347
1348 if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or1348 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}
113113
114pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void {114pub 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}
119128
...@@ -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!
12161225
1217fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {1226fn 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}
12211239
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{
1010
11pub fn addCases(ctx: *TestContext) !void {11pub 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 values42 // 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 {
2626
27 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});27 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
2828
29 case.addError(
30 \\export fn _start() noreturn {
31 \\}
32 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
33
29 // Regular old hello world34 // Regular old hello world
30 case.addCompareOutput(35 case.addCompareOutput(
31 \\export fn _start() noreturn {36 \\export fn _start() noreturn {