Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 28 additions & 22 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9714,18 +9714,18 @@ fn funcCommon(
{
return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
}

if (cc_resolved == .Interrupt) switch (target.cpu.arch) {
.x86, .x86_64 => {
switch (cc_resolved) {
.Interrupt => if (target.cpu.arch.isX86()) {
const err_code_size = target.ptrBitWidth();
switch (i) {
0 => if (param_ty.zigTypeTag(mod) != .Pointer) return sema.fail(block, param_src, "parameter must be a pointer type", .{}),
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}),
else => return sema.fail(block, param_src, "Interrupt calling convention supports up to 2 parameters, found {d}", .{i + 1}),
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", .{}),
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}),
else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}),
}
},
else => return sema.fail(block, param_src, "parameters are not allowed with Interrupt calling convention", .{}),
};
} else return sema.fail(block, param_src, "parameters are not allowed with 'Interrupt' calling convention", .{}),
.Signal => return sema.fail(block, param_src, "parameters are not allowed with 'Signal' calling convention", .{}),
else => {},
}
}

var ret_ty_requires_comptime = false;
Expand Down Expand Up @@ -10031,6 +10031,16 @@ fn finishFunc(
return sema.failWithOwnedErrorMsg(block, msg);
}

switch (cc_resolved) {
.Interrupt, .Signal => if (return_type.zigTypeTag(mod) != .Void and return_type.zigTypeTag(mod) != .NoReturn) {
return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
},
.Inline => if (is_noinline) {
return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
},
else => {},
}

const arch = target.cpu.arch;
if (@as(?[]const u8, switch (cc_resolved) {
.Unspecified, .C, .Naked, .Async, .Inline => null,
Expand Down Expand Up @@ -10074,20 +10084,7 @@ fn finishFunc(
});
}

if (cc_resolved == .Interrupt and return_type.zigTypeTag(mod) != .Void) {
return sema.fail(
block,
cc_src,
"non-void return type '{}' not allowed in function with calling convention 'Interrupt'",
.{return_type.fmt(mod)},
);
}

if (cc_resolved == .Inline and is_noinline) {
return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
}
if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;

if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {
// Make sure that StackTrace's fields are resolved so that the backend can
// lower this fn type.
Expand Down Expand Up @@ -22722,7 +22719,16 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
.storage = .{ .elems = new_elems },
} }));
}
if (try sema.typeRequiresComptime(ptr_ty)) {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(block, src, "pointer to comptime-only type '{}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(mod)});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const msg = try sema.errMsg(block, src, "cannot get a runtime pointer to comptime-only type '{}'", .{ptr_ty.fmt(mod)});
const msg = try sema.errMsg(block, src, "pointer to comptime-only type '{}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(mod)});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit verbose but I do like it better.

errdefer msg.destroy(sema.gpa);

const src_decl = mod.declPtr(block.src_decl);
try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), ptr_ty);
break :msg msg;
});
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (!is_vector) {
if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
Expand Down
20 changes: 20 additions & 0 deletions test/cases/compile_errors/invalid_func_for_callconv.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export fn interrupt_param1(_: u32) callconv(.Interrupt) void {}
export fn interrupt_param2(_: *anyopaque, _: u32) callconv(.Interrupt) void {}
export fn interrupt_param3(_: *anyopaque, _: u64, _: u32) callconv(.Interrupt) void {}
export fn interrupt_ret(_: *anyopaque, _: u64) callconv(.Interrupt) u32 {
return 0;
}

export fn signal_param(_: u32) callconv(.Signal) void {}
export fn signal_ret() callconv(.Signal) noreturn {}

// error
// backend=stage2
// target=x86_64-linux
//
// :1:28: error: first parameter of function with 'Interrupt' calling convention must be a pointer type
// :2:43: error: second parameter of function with 'Interrupt' calling convention must be a 64-bit integer
// :3:51: error: 'Interrupt' calling convention supports up to 2 parameters, found 3
// :4:69: error: function with calling convention 'Interrupt' must return 'void' or 'noreturn'
// :8:24: error: parameters are not allowed with 'Signal' calling convention
// :9:34: error: callconv 'Signal' is only available on AVR, not x86_64
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const GuSettings = struct {
fin: ?fn (c_int) callconv(.C) void,
};
pub export fn callbackFin(id: c_int, arg: ?*anyopaque) void {
const settings: ?*GuSettings = @as(?*GuSettings, @ptrFromInt(@intFromPtr(arg)));
if (settings.?.fin != null) {
settings.?.fin.?(id & 0xffff);
}
}

// error
// target=native
//
// :5:54: error: pointer to comptime-only type '?*tmp.GuSettings' must be comptime-known, but operand is runtime-known
// :2:10: note: struct requires comptime because of this field
// :2:10: note: use '*const fn (c_int) callconv(.C) void' for a function pointer type