From b757a96d5c885442c38e217006d75c85a28daf09 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Tue, 9 Aug 2022 23:37:26 +0300 Subject: [PATCH] Sema: add declared here note to function call errors --- src/Sema.zig | 92 +++++++++++-------- ...function_with_naked_calling_convention.zig | 11 +++ .../member_function_arg_mismatch.zig | 3 +- ...function_with_naked_calling_convention.zig | 11 --- ...number_of_arguments_for_method_fn_call.zig | 14 --- .../wrong_number_of_arguments.zig | 3 +- ...number_of_arguments_for_method_fn_call.zig | 15 +++ 7 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 test/cases/compile_errors/calling_function_with_naked_calling_convention.zig delete mode 100644 test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig delete mode 100644 test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig create mode 100644 test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig diff --git a/src/Sema.zig b/src/Sema.zig index 68409a5d05..acdce0e9b0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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) { diff --git a/test/cases/compile_errors/calling_function_with_naked_calling_convention.zig b/test/cases/compile_errors/calling_function_with_naked_calling_convention.zig new file mode 100644 index 0000000000..54bf585425 --- /dev/null +++ b/test/cases/compile_errors/calling_function_with_naked_calling_convention.zig @@ -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 diff --git a/test/cases/compile_errors/member_function_arg_mismatch.zig b/test/cases/compile_errors/member_function_arg_mismatch.zig index aaefac58b4..b739be9544 100644 --- a/test/cases/compile_errors/member_function_arg_mismatch.zig +++ b/test/cases/compile_errors/member_function_arg_mismatch.zig @@ -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 diff --git a/test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig b/test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig deleted file mode 100644 index 401f84e687..0000000000 --- a/test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig +++ /dev/null @@ -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 diff --git a/test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig b/test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig deleted file mode 100644 index 7371223863..0000000000 --- a/test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig +++ /dev/null @@ -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 diff --git a/test/cases/compile_errors/wrong_number_of_arguments.zig b/test/cases/compile_errors/wrong_number_of_arguments.zig index 64eb11650a..05d761de18 100644 --- a/test/cases/compile_errors/wrong_number_of_arguments.zig +++ b/test/cases/compile_errors/wrong_number_of_arguments.zig @@ -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 diff --git a/test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig b/test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig new file mode 100644 index 0000000000..da6a7be4fa --- /dev/null +++ b/test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig @@ -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