authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-05-10 18:09:51+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-06-02 21:42:13+03:00
log15791b8b1a426ebb524bb2c6312f2da66a540dbe
tree76223224d4b11d243a793234075fbe2d03883b2f
parent17a0458e530242254f21fc0b6825e1303ec06028

Sema: validate function signature for Signal calling convention


2 files changed, 39 insertions(+), 22 deletions(-)

src/Sema.zig+19-22
...@@ -9714,18 +9714,18 @@ fn funcCommon(...@@ -9714,18 +9714,18 @@ fn funcCommon(
9714 {9714 {
9715 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});9715 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
9716 }9716 }
97179717 switch (cc_resolved) {
9718 if (cc_resolved == .Interrupt) switch (target.cpu.arch) {9718 .Interrupt => if (target.cpu.arch.isX86()) {
9719 .x86, .x86_64 => {
9720 const err_code_size = target.ptrBitWidth();9719 const err_code_size = target.ptrBitWidth();
9721 switch (i) {9720 switch (i) {
9722 0 => if (param_ty.zigTypeTag(mod) != .Pointer) return sema.fail(block, param_src, "parameter must be a pointer type", .{}),9721 0 => if (param_ty.zigTypeTag(mod) != .Pointer) return sema.fail(block, param_src, "first parameter of function with 'Interrupt' calling convention must be a pointer type", .{}),
9723 1 => if (param_ty.bitSize(mod) != err_code_size) return sema.fail(block, param_src, "parameter must be a {d}-bit integer", .{err_code_size}),9722 1 => if (param_ty.bitSize(mod) != err_code_size) return sema.fail(block, param_src, "second parameter of function with 'Interrupt' calling convention must be a {d}-bit integer", .{err_code_size}),
9724 else => return sema.fail(block, param_src, "Interrupt calling convention supports up to 2 parameters, found {d}", .{i + 1}),9723 else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}),
9725 }9724 }
9726 },9725 } else return sema.fail(block, param_src, "parameters are not allowed with 'Interrupt' calling convention", .{}),
9727 else => return sema.fail(block, param_src, "parameters are not allowed with Interrupt calling convention", .{}),9726 .Signal => return sema.fail(block, param_src, "parameters are not allowed with 'Signal' calling convention", .{}),
9728 };9727 else => {},
9728 }
9729 }9729 }
97309730
9731 var ret_ty_requires_comptime = false;9731 var ret_ty_requires_comptime = false;
...@@ -10031,6 +10031,16 @@ fn finishFunc(...@@ -10031,6 +10031,16 @@ fn finishFunc(
10031 return sema.failWithOwnedErrorMsg(block, msg);10031 return sema.failWithOwnedErrorMsg(block, msg);
10032 }10032 }
1003310033
10034 switch (cc_resolved) {
10035 .Interrupt, .Signal => if (return_type.zigTypeTag(mod) != .Void and return_type.zigTypeTag(mod) != .NoReturn) {
10036 return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
10037 },
10038 .Inline => if (is_noinline) {
10039 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
10040 },
10041 else => {},
10042 }
10043
10034 const arch = target.cpu.arch;10044 const arch = target.cpu.arch;
10035 if (@as(?[]const u8, switch (cc_resolved) {10045 if (@as(?[]const u8, switch (cc_resolved) {
10036 .Unspecified, .C, .Naked, .Async, .Inline => null,10046 .Unspecified, .C, .Naked, .Async, .Inline => null,
...@@ -10074,20 +10084,7 @@ fn finishFunc(...@@ -10074,20 +10084,7 @@ fn finishFunc(
10074 });10084 });
10075 }10085 }
1007610086
10077 if (cc_resolved == .Interrupt and return_type.zigTypeTag(mod) != .Void) {
10078 return sema.fail(
10079 block,
10080 cc_src,
10081 "non-void return type '{}' not allowed in function with calling convention 'Interrupt'",
10082 .{return_type.fmt(mod)},
10083 );
10084 }
10085
10086 if (cc_resolved == .Inline and is_noinline) {
10087 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
10088 }
10089 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;10087 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
10090
10091 if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {10088 if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {
10092 // Make sure that StackTrace's fields are resolved so that the backend can10089 // Make sure that StackTrace's fields are resolved so that the backend can
10093 // lower this fn type.10090 // lower this fn type.
test/cases/compile_errors/invalid_func_for_callconv.zig created+20
...@@ -0,0 +1,20 @@
1export fn interrupt_param1(_: u32) callconv(.Interrupt) void {}
2export fn interrupt_param2(_: *anyopaque, _: u32) callconv(.Interrupt) void {}
3export fn interrupt_param3(_: *anyopaque, _: u64, _: u32) callconv(.Interrupt) void {}
4export fn interrupt_ret(_: *anyopaque, _: u64) callconv(.Interrupt) u32 {
5 return 0;
6}
7
8export fn signal_param(_: u32) callconv(.Signal) void {}
9export fn signal_ret() callconv(.Signal) noreturn {}
10
11// error
12// backend=stage2
13// target=x86_64-linux
14//
15// :1:28: error: first parameter of function with 'Interrupt' calling convention must be a pointer type
16// :2:43: error: second parameter of function with 'Interrupt' calling convention must be a 64-bit integer
17// :3:51: error: 'Interrupt' calling convention supports up to 2 parameters, found 3
18// :4:69: error: function with calling convention 'Interrupt' must return 'void' or 'noreturn'
19// :8:24: error: parameters are not allowed with 'Signal' calling convention
20// :9:34: error: callconv 'Signal' is only available on AVR, not x86_64