From 10ff50d7d8d616254c4705d86f345c8913b52bcb Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 11 May 2012 05:16:41 +0000 Subject: [PATCH] PR11857: When the wrong number of arguments are provided for a function which expects exactly one argument, include the name of the argument in the diagnostic text. Patch by Terry Long! llvm-svn: 156607 --- .../clang/Basic/DiagnosticSemaKinds.td | 19 +++++++++++++++++++ clang/lib/Sema/SemaExpr.cpp | 17 ++++++++++++----- clang/lib/Sema/SemaOverload.cpp | 11 ++++++++--- clang/test/Sema/exprs.c | 10 ++++++++-- clang/test/SemaCXX/default1.cpp | 2 +- clang/test/SemaCXX/overload-call.cpp | 10 ++++++++-- clang/test/SemaCXX/overload-member-call.cpp | 13 +++++++++++-- 7 files changed, 67 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2aec5dba16b0..90c1551b2ce8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2039,6 +2039,17 @@ def note_ovl_candidate_arity : Note<"candidate " "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " "%plural{1:was|:were}4 provided">; +def note_ovl_candidate_arity_one : Note<"candidate " + "%select{function|function|constructor|function|function|constructor|" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 %select{|template }1" + "not viable: requires%select{ at least| at most|}2 argument %3, but " + "%plural{0:none|:%4}4 were provided">; + def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" "function |function |constructor |" @@ -4558,10 +4569,18 @@ def err_typecheck_call_too_few_args : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2">; +def err_typecheck_call_too_few_args_one : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "argument %1 was not specified">; def err_typecheck_call_too_few_args_at_least : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at least %1, have %2">; +def err_typecheck_call_too_few_args_at_least_one : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "at least argument %1 must be specified">; def err_typecheck_call_too_many_args : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3ab0723ab06f..0f9793d8394f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3380,11 +3380,18 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { if (NumArgs < MinArgs) { - Diag(RParenLoc, MinArgs == NumArgsInProto - ? diag::err_typecheck_call_too_few_args - : diag::err_typecheck_call_too_few_args_at_least) - << FnKind - << MinArgs << NumArgs << Fn->getSourceRange(); + if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName()) + Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic() + ? diag::err_typecheck_call_too_few_args_one + : diag::err_typecheck_call_too_few_args_at_least_one) + << FnKind + << FDecl->getParamDecl(0) << Fn->getSourceRange(); + else + Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic() + ? diag::err_typecheck_call_too_few_args + : diag::err_typecheck_call_too_few_args_at_least) + << FnKind + << MinArgs << NumArgs << Fn->getSourceRange(); // Emit the location of the prototype. if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index b99a638bdac7..2068006c29ce 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8149,9 +8149,14 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, std::string Description; OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode - << modeCount << NumFormalArgs; + if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName()) + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << Fn->getParamDecl(0) << NumFormalArgs; + else + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) + << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode + << modeCount << NumFormalArgs; MaybeEmitInheritedConstructorNote(S, Fn); } diff --git a/clang/test/Sema/exprs.c b/clang/test/Sema/exprs.c index 72cff65f4837..8bedd6dd01a7 100644 --- a/clang/test/Sema/exprs.c +++ b/clang/test/Sema/exprs.c @@ -162,11 +162,17 @@ void test17(int x) { x = sizeof(x/0); // no warning. } -// PR6501 +// PR6501 & PR11857 void test18_a(int a); // expected-note 2 {{'test18_a' declared here}} +void test18_b(int); // expected-note {{'test18_b' declared here}} +void test18_c(int a, int b); // expected-note {{'test18_c' declared here}} +void test18_d(int a, ...); // expected-note {{'test18_d' declared here}} void test18(int b) { test18_a(b, b); // expected-error {{too many arguments to function call, expected 1, have 2}} - test18_a(); // expected-error {{too few arguments to function call, expected 1, have 0}} + test18_a(); // expected-error {{too few arguments to function call, argument 'a' was not specified}} + test18_b(); // expected-error {{too few arguments to function call, expected 1, have 0}} + test18_c(b); // expected-error {{too few arguments to function call, expected 2, have 1}} + test18_d(); // expected-error {{too few arguments to function call, at least argument 'a' must be specified}} } // PR7569 diff --git a/clang/test/SemaCXX/default1.cpp b/clang/test/SemaCXX/default1.cpp index ae6ef9791c2a..a911e20b12a0 100644 --- a/clang/test/SemaCXX/default1.cpp +++ b/clang/test/SemaCXX/default1.cpp @@ -47,6 +47,6 @@ int i () { void j (int f = 4); { void j (int f); // expected-note{{'j' declared here}} - j(); // expected-error{{too few arguments to function call, expected 1, have 0}} + j(); // expected-error{{too few arguments to function call, argument 'f' was not specified}} } } diff --git a/clang/test/SemaCXX/overload-call.cpp b/clang/test/SemaCXX/overload-call.cpp index b5e121486621..db994441ab7e 100644 --- a/clang/test/SemaCXX/overload-call.cpp +++ b/clang/test/SemaCXX/overload-call.cpp @@ -319,14 +319,20 @@ namespace PR5756 { namespace test1 { template void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}} void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} - void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}} - void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}} void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} + // PR 11857 + void foo(int n); // expected-note {{candidate function not viable: requires argument 'n', but 2 were provided}} + void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most argument 'n', but 2 were provided}} + void bar(int n, int u = 0); // expected-note {{candidate function not viable: requires at least argument 'n', but none were provided}} + void baz(int n = 0, int u = 0); // expected-note {{candidate function not viable: requires at most 2 arguments, but 3 were provided}} + void test() { foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}} + bar(); //expected-error {{no matching function for call to 'bar'}} + baz(3, 4, 5); // expected-error {{no matching function for call to 'baz'}} } } diff --git a/clang/test/SemaCXX/overload-member-call.cpp b/clang/test/SemaCXX/overload-member-call.cpp index 37c955201a98..31dac19a1241 100644 --- a/clang/test/SemaCXX/overload-member-call.cpp +++ b/clang/test/SemaCXX/overload-member-call.cpp @@ -72,8 +72,6 @@ namespace test1 { class A { template void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}} void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} - void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}} - void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}} void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} @@ -83,6 +81,14 @@ namespace test1 { void baz(A &d); // expected-note {{candidate function not viable: 1st argument ('const test1::A') would lose const qualifier}} void baz(int i); // expected-note {{candidate function not viable: no known conversion from 'const test1::A' to 'int' for 1st argument}} + + // PR 11857 + void foo(int n); // expected-note {{candidate function not viable: requires argument 'n', but 2 were provided}} + void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most argument 'n', but 2 were provided}} + void rab(double n, int u = 0); // expected-note {{candidate function not viable: requires at least argument 'n', but none were provided}} + void rab(int n, int u = 0); // expected-note {{candidate function not viable: requires at least argument 'n', but none were provided}} + void zab(double n = 0.0, int u = 0); // expected-note {{candidate function not viable: requires at most 2 arguments, but 3 were provided}} + void zab(int n = 0, int u = 0); // expected-note {{candidate function not viable: requires at most 2 arguments, but 3 were provided}} }; void test() { @@ -93,6 +99,9 @@ namespace test1 { b.bar(0); //expected-error {{no matching member function for call to 'bar'}} a.baz(b); //expected-error {{no matching member function for call to 'baz'}} + + a.rab(); //expected-error {{no matching member function for call to 'rab'}} + a.zab(3, 4, 5); //expected-error {{no matching member function for call to 'zab'}} } }