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 {
41864186 .owner_decl = new_decl,
41874187 .owner_decl_index = new_decl_index,
41884188 .func_index = .none,
4189 .func_is_naked = false,
41894190 .fn_ret_ty = Type.void,
41904191 .fn_ret_ty_ies = null,
41914192 .owner_func_index = .none,
......@@ -4268,6 +4269,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
42684269 .owner_decl = decl,
42694270 .owner_decl_index = decl_index,
42704271 .func_index = .none,
4272 .func_is_naked = false,
42714273 .fn_ret_ty = Type.void,
42724274 .fn_ret_ty_ies = null,
42734275 .owner_func_index = .none,
......@@ -5213,6 +5215,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
52135215 .owner_decl = decl,
52145216 .owner_decl_index = decl_index,
52155217 .func_index = func_index,
5218 .func_is_naked = fn_ty_info.cc == .Naked,
52165219 .fn_ret_ty = fn_ty_info.return_type.toType(),
52175220 .fn_ret_ty_ies = null,
52185221 .owner_func_index = func_index,
src/Sema.zig+28-3
......@@ -30,6 +30,8 @@ owner_func_index: InternPool.Index,
3030/// an inline or comptime function call.
3131/// This could be `none`, a `func_decl`, or a `func_instance`.
3232func_index: InternPool.Index,
33/// Whether the type of func_index has a calling convention of `.Naked`.
34func_is_naked: bool,
3335/// Used to restore the error return trace when returning a non-error from a function.
3436error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
3537/// When semantic analysis needs to know the return type of the function whose body
......@@ -6827,6 +6829,10 @@ fn analyzeCall(
68276829 var is_inline_call = is_comptime_call or modifier == .always_inline or
68286830 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
68306836 if (!is_inline_call and is_generic_call) {
68316837 if (sema.instantiateGenericCall(
68326838 block,
......@@ -7509,6 +7515,9 @@ fn instantiateGenericCall(
75097515 .owner_decl = sema.owner_decl,
75107516 .owner_decl_index = sema.owner_decl_index,
75117517 .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,
75127521 .fn_ret_ty = Type.void,
75137522 .fn_ret_ty_ies = null,
75147523 .owner_func_index = .none,
......@@ -18193,10 +18202,20 @@ fn zirRetImplicit(
1819318202 const tracy = trace(@src());
1819418203 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
1819618216 const mod = sema.mod;
1819718217 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1819818218 const operand = try sema.resolveInst(inst_data.operand);
18199
1820018219 const r_brace_src = inst_data.src();
1820118220 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
1820218221 const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);
......@@ -18222,7 +18241,7 @@ fn zirRetImplicit(
1822218241 return sema.failWithOwnedErrorMsg(msg);
1822318242 }
1822418243
18225 return sema.analyzeRet(block, operand, .unneeded);
18244 return sema.analyzeRet(block, operand, r_brace_src);
1822618245}
1822718246
1822818247fn 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
1824418263 const src = inst_data.src();
1824518264 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) {
1824818267 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
1824918268 return sema.analyzeRet(block, operand, src);
1825018269 }
......@@ -18450,6 +18469,8 @@ fn analyzeRet(
1845018469 return always_noreturn;
1845118470 } else if (block.is_comptime) {
1845218471 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", .{});
1845318474 }
1845418475
1845518476 try sema.resolveTypeLayout(sema.fn_ret_ty);
......@@ -33571,6 +33592,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3357133592 .owner_decl = decl,
3357233593 .owner_decl_index = decl_index,
3357333594 .func_index = .none,
33595 .func_is_naked = false,
3357433596 .fn_ret_ty = Type.void,
3357533597 .fn_ret_ty_ies = null,
3357633598 .owner_func_index = .none,
......@@ -33622,6 +33644,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3362233644 .owner_decl = decl,
3362333645 .owner_decl_index = decl_index,
3362433646 .func_index = .none,
33647 .func_is_naked = false,
3362533648 .fn_ret_ty = Type.void,
3362633649 .fn_ret_ty_ies = null,
3362733650 .owner_func_index = .none,
......@@ -34405,6 +34428,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3440534428 .owner_decl = decl,
3440634429 .owner_decl_index = decl_index,
3440734430 .func_index = .none,
34431 .func_is_naked = false,
3440834432 .fn_ret_ty = Type.void,
3440934433 .fn_ret_ty_ies = null,
3441034434 .owner_func_index = .none,
......@@ -34748,6 +34772,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3474834772 .owner_decl = decl,
3474934773 .owner_decl_index = decl_index,
3475034774 .func_index = .none,
34775 .func_is_naked = false,
3475134776 .fn_ret_ty = Type.void,
3475234777 .fn_ret_ty_ies = null,
3475334778 .owner_func_index = .none,