authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-31 01:50:54-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-31 01:58:10-04:00
log2ba787e3038d8776599fb968b3ddec6b7a62a3f3
tree967663a3f1226f48ac1405416f7bc002074430da
parent9831f272383a66392ebeadbc60d8176f44b3553c

Sema: restrict what can appear in a naked function

* Disable runtime calls, since it is not possible to know the proper stack adjustment to follow the callee abi. * Disable runtime returns, since it is not possible to know where the return address is stored in general. * Allow implicit returns regardless of the return type, which allows naked functions with a non-void return type to be written.

2 files changed, 31 insertions(+), 3 deletions(-)

src/Module.zig+3
...@@ -4186,6 +4186,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -4186,6 +4186,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4186 .owner_decl = new_decl,4186 .owner_decl = new_decl,
4187 .owner_decl_index = new_decl_index,4187 .owner_decl_index = new_decl_index,
4188 .func_index = .none,4188 .func_index = .none,
4189 .func_is_naked = false,
4189 .fn_ret_ty = Type.void,4190 .fn_ret_ty = Type.void,
4190 .fn_ret_ty_ies = null,4191 .fn_ret_ty_ies = null,
4191 .owner_func_index = .none,4192 .owner_func_index = .none,
...@@ -4268,6 +4269,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4268,6 +4269,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4268 .owner_decl = decl,4269 .owner_decl = decl,
4269 .owner_decl_index = decl_index,4270 .owner_decl_index = decl_index,
4270 .func_index = .none,4271 .func_index = .none,
4272 .func_is_naked = false,
4271 .fn_ret_ty = Type.void,4273 .fn_ret_ty = Type.void,
4272 .fn_ret_ty_ies = null,4274 .fn_ret_ty_ies = null,
4273 .owner_func_index = .none,4275 .owner_func_index = .none,
...@@ -5213,6 +5215,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -5213,6 +5215,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
5213 .owner_decl = decl,5215 .owner_decl = decl,
5214 .owner_decl_index = decl_index,5216 .owner_decl_index = decl_index,
5215 .func_index = func_index,5217 .func_index = func_index,
5218 .func_is_naked = fn_ty_info.cc == .Naked,
5216 .fn_ret_ty = fn_ty_info.return_type.toType(),5219 .fn_ret_ty = fn_ty_info.return_type.toType(),
5217 .fn_ret_ty_ies = null,5220 .fn_ret_ty_ies = null,
5218 .owner_func_index = func_index,5221 .owner_func_index = func_index,
src/Sema.zig+28-3
...@@ -30,6 +30,8 @@ owner_func_index: InternPool.Index,...@@ -30,6 +30,8 @@ owner_func_index: InternPool.Index,
30/// an inline or comptime function call.30/// an inline or comptime function call.
31/// This could be `none`, a `func_decl`, or a `func_instance`.31/// This could be `none`, a `func_decl`, or a `func_instance`.
32func_index: InternPool.Index,32func_index: InternPool.Index,
33/// Whether the type of func_index has a calling convention of `.Naked`.
34func_is_naked: bool,
33/// Used to restore the error return trace when returning a non-error from a function.35/// Used to restore the error return trace when returning a non-error from a function.
34error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,36error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
35/// When semantic analysis needs to know the return type of the function whose body37/// When semantic analysis needs to know the return type of the function whose body
...@@ -6827,6 +6829,10 @@ fn analyzeCall(...@@ -6827,6 +6829,10 @@ fn analyzeCall(
6827 var is_inline_call = is_comptime_call or modifier == .always_inline or6829 var is_inline_call = is_comptime_call or modifier == .always_inline or
6828 func_ty_info.cc == .Inline;6830 func_ty_info.cc == .Inline;
68296831
6832 if (sema.func_is_naked and !is_inline_call and !is_comptime_call) {
6833 return sema.fail(block, call_src, "runtime call not allowed in naked function", .{});
6834 }
6835
6830 if (!is_inline_call and is_generic_call) {6836 if (!is_inline_call and is_generic_call) {
6831 if (sema.instantiateGenericCall(6837 if (sema.instantiateGenericCall(
6832 block,6838 block,
...@@ -7509,6 +7515,9 @@ fn instantiateGenericCall(...@@ -7509,6 +7515,9 @@ fn instantiateGenericCall(
7509 .owner_decl = sema.owner_decl,7515 .owner_decl = sema.owner_decl,
7510 .owner_decl_index = sema.owner_decl_index,7516 .owner_decl_index = sema.owner_decl_index,
7511 .func_index = sema.owner_func_index,7517 .func_index = sema.owner_func_index,
7518 // This may not be known yet, since the calling convention could be generic, but there
7519 // should be no illegal instructions encountered while creating the function anyway.
7520 .func_is_naked = false,
7512 .fn_ret_ty = Type.void,7521 .fn_ret_ty = Type.void,
7513 .fn_ret_ty_ies = null,7522 .fn_ret_ty_ies = null,
7514 .owner_func_index = .none,7523 .owner_func_index = .none,
...@@ -18193,10 +18202,20 @@ fn zirRetImplicit(...@@ -18193,10 +18202,20 @@ fn zirRetImplicit(
18193 const tracy = trace(@src());18202 const tracy = trace(@src());
18194 defer tracy.end();18203 defer tracy.end();
1819518204
18205 if (block.inlining == null and sema.func_is_naked) {
18206 assert(!block.is_comptime);
18207 if (block.wantSafety()) {
18208 // Calling a safety function from a naked function would not be legal.
18209 _ = try block.addNoOp(.trap);
18210 } else {
18211 try block.addUnreachable(false);
18212 }
18213 return always_noreturn;
18214 }
18215
18196 const mod = sema.mod;18216 const mod = sema.mod;
18197 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;18217 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
18198 const operand = try sema.resolveInst(inst_data.operand);18218 const operand = try sema.resolveInst(inst_data.operand);
18199
18200 const r_brace_src = inst_data.src();18219 const r_brace_src = inst_data.src();
18201 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };18220 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
18202 const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);18221 const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);
...@@ -18222,7 +18241,7 @@ fn zirRetImplicit(...@@ -18222,7 +18241,7 @@ fn zirRetImplicit(
18222 return sema.failWithOwnedErrorMsg(msg);18241 return sema.failWithOwnedErrorMsg(msg);
18223 }18242 }
1822418243
18225 return sema.analyzeRet(block, operand, .unneeded);18244 return sema.analyzeRet(block, operand, r_brace_src);
18226}18245}
1822718246
18228fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {18247fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
...@@ -18244,7 +18263,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir...@@ -18244,7 +18263,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
18244 const src = inst_data.src();18263 const src = inst_data.src();
18245 const ret_ptr = try sema.resolveInst(inst_data.operand);18264 const ret_ptr = try sema.resolveInst(inst_data.operand);
1824618265
18247 if (block.is_comptime or block.inlining != null) {18266 if (block.is_comptime or block.inlining != null or sema.func_is_naked) {
18248 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);18267 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
18249 return sema.analyzeRet(block, operand, src);18268 return sema.analyzeRet(block, operand, src);
18250 }18269 }
...@@ -18450,6 +18469,8 @@ fn analyzeRet(...@@ -18450,6 +18469,8 @@ fn analyzeRet(
18450 return always_noreturn;18469 return always_noreturn;
18451 } else if (block.is_comptime) {18470 } else if (block.is_comptime) {
18452 return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});18471 return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});
18472 } else if (sema.func_is_naked) {
18473 return sema.fail(block, src, "cannot return from naked function", .{});
18453 }18474 }
1845418475
18455 try sema.resolveTypeLayout(sema.fn_ret_ty);18476 try sema.resolveTypeLayout(sema.fn_ret_ty);
...@@ -33571,6 +33592,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -33571,6 +33592,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
33571 .owner_decl = decl,33592 .owner_decl = decl,
33572 .owner_decl_index = decl_index,33593 .owner_decl_index = decl_index,
33573 .func_index = .none,33594 .func_index = .none,
33595 .func_is_naked = false,
33574 .fn_ret_ty = Type.void,33596 .fn_ret_ty = Type.void,
33575 .fn_ret_ty_ies = null,33597 .fn_ret_ty_ies = null,
33576 .owner_func_index = .none,33598 .owner_func_index = .none,
...@@ -33622,6 +33644,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -33622,6 +33644,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
33622 .owner_decl = decl,33644 .owner_decl = decl,
33623 .owner_decl_index = decl_index,33645 .owner_decl_index = decl_index,
33624 .func_index = .none,33646 .func_index = .none,
33647 .func_is_naked = false,
33625 .fn_ret_ty = Type.void,33648 .fn_ret_ty = Type.void,
33626 .fn_ret_ty_ies = null,33649 .fn_ret_ty_ies = null,
33627 .owner_func_index = .none,33650 .owner_func_index = .none,
...@@ -34405,6 +34428,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -34405,6 +34428,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
34405 .owner_decl = decl,34428 .owner_decl = decl,
34406 .owner_decl_index = decl_index,34429 .owner_decl_index = decl_index,
34407 .func_index = .none,34430 .func_index = .none,
34431 .func_is_naked = false,
34408 .fn_ret_ty = Type.void,34432 .fn_ret_ty = Type.void,
34409 .fn_ret_ty_ies = null,34433 .fn_ret_ty_ies = null,
34410 .owner_func_index = .none,34434 .owner_func_index = .none,
...@@ -34748,6 +34772,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -34748,6 +34772,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
34748 .owner_decl = decl,34772 .owner_decl = decl,
34749 .owner_decl_index = decl_index,34773 .owner_decl_index = decl_index,
34750 .func_index = .none,34774 .func_index = .none,
34775 .func_is_naked = false,
34751 .fn_ret_ty = Type.void,34776 .fn_ret_ty = Type.void,
34752 .fn_ret_ty_ies = null,34777 .fn_ret_ty_ies = null,
34753 .owner_func_index = .none,34778 .owner_func_index = .none,