Sema: add declared here note to function call errors

This commit is contained in:
Veikka Tuominen 2022-08-09 23:37:26 +03:00
parent 0778490283
commit b757a96d5c
7 changed files with 83 additions and 66 deletions

View File

@ -5409,6 +5409,19 @@ fn lookupInNamespace(
return null;
}
fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null;
if (func_val.isUndef()) return null;
const owner_decl_index = switch (func_val.tag()) {
.extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl,
.function => func_val.castTag(.function).?.data.owner_decl,
.decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
else => return null,
};
const owner_decl = sema.mod.declPtr(owner_decl_index);
return owner_decl.srcLoc();
}
fn zirCall(
sema: *Sema,
block: *Block,
@ -5464,41 +5477,35 @@ fn zirCall(
const func_ty_info = func_ty.fnInfo();
const fn_params_len = func_ty_info.param_types.len;
if (func_ty_info.is_var_args) {
assert(func_ty_info.cc == .C);
if (total_args < fn_params_len) {
// TODO add error note: declared here
if (bound_arg_src != null) {
return sema.fail(
block,
call_src,
"member function expected at least {d} argument(s), found {d}",
.{ fn_params_len - 1, args_len },
);
}
return sema.fail(
check_args: {
if (func_ty_info.is_var_args) {
assert(func_ty_info.cc == .C);
if (total_args >= fn_params_len) break :check_args;
} else if (fn_params_len == total_args) {
break :check_args;
}
const decl_src = try sema.funcDeclSrc(block, func_src, func);
const member_str = if (bound_arg_src != null) "member function " else "";
const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
const msg = msg: {
const msg = try sema.errMsg(
block,
func_src,
"expected at least {d} argument(s), found {d}",
.{ fn_params_len, args_len },
"{s}expected {s}{d} argument(s), found {d}",
.{
member_str,
variadic_str,
fn_params_len - @boolToInt(bound_arg_src != null),
args_len,
},
);
}
} else if (fn_params_len != total_args) {
// TODO add error note: declared here
if (bound_arg_src != null) {
return sema.fail(
block,
call_src,
"member function expected {d} argument(s), found {d}",
.{ fn_params_len - 1, args_len },
);
}
return sema.fail(
block,
call_src,
"expected {d} argument(s), found {d}",
.{ fn_params_len, args_len },
);
errdefer msg.destroy(sema.gpa);
if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
const args_body = sema.code.extra[extra.end..];
@ -5625,13 +5632,20 @@ fn analyzeCall(
const func_ty_info = func_ty.fnInfo();
const cc = func_ty_info.cc;
if (cc == .Naked) {
// TODO add error note: declared here
return sema.fail(
block,
func_src,
"unable to call function with naked calling convention",
.{},
);
const decl_src = try sema.funcDeclSrc(block, func_src, func);
const msg = msg: {
const msg = try sema.errMsg(
block,
func_src,
"unable to call function with naked calling convention",
.{},
);
errdefer msg.destroy(sema.gpa);
if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
const fn_params_len = func_ty_info.param_types.len;
if (func_ty_info.is_var_args) {

View File

@ -0,0 +1,11 @@
export fn entry() void {
foo();
}
fn foo() callconv(.Naked) void { }
// error
// backend=llvm
// target=native
//
// :2:5: error: unable to call function with naked calling convention
// :4:1: note: function declared here

View File

@ -11,4 +11,5 @@ pub export fn entry() void {
// backend=stage2
// target=native
//
// :7:10: error: member function expected 2 argument(s), found 1
// :7:6: error: member function expected 2 argument(s), found 1
// :3:5: note: function declared here

View File

@ -1,11 +0,0 @@
export fn entry() void {
foo();
}
fn foo() callconv(.Naked) void { }
// error
// backend=stage1
// target=native
//
// tmp.zig:2:5: error: unable to call function with naked calling convention
// tmp.zig:4:1: note: declared here

View File

@ -1,14 +0,0 @@
const Foo = struct {
fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
};
fn f(foo: *const Foo) void {
foo.method(1, 2);
}
export fn entry() usize { return @sizeOf(@TypeOf(f)); }
// error
// backend=stage1
// target=native
//
// tmp.zig:6:15: error: expected 2 argument(s), found 3

View File

@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }
// backend=stage2
// target=native
//
// :2:6: error: expected 3 argument(s), found 1
// :2:5: error: expected 3 argument(s), found 1
// :4:1: note: function declared here

View File

@ -0,0 +1,15 @@
const Foo = struct {
fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
};
fn f(foo: *const Foo) void {
foo.method(1, 2);
}
export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
// error
// backend=stage2
// target=native
//
// :6:8: error: member function expected 1 argument(s), found 2
// :2:5: note: function declared here