diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e4df72ec1a377acd6000faf28f969b9eaed7ca04..80e6121ce440d27a6ae0d48dd2289b4edd2a6cff 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -455,8 +455,8 @@ struct rejection_reason { int expected; /* The actual number of arguments in the call. */ int actual; - /* Whether the call was a varargs call. */ - bool call_varargs_p; + /* Whether EXPECTED should be treated as a lower bound. */ + bool least_p; } arity; /* Information about an argument conversion mismatch. */ struct conversion_info conversion; @@ -628,12 +628,13 @@ alloc_rejection (enum rejection_reason_code code) } static struct rejection_reason * -arity_rejection (tree first_arg, int expected, int actual) +arity_rejection (tree first_arg, int expected, int actual, bool least_p = false) { struct rejection_reason *r = alloc_rejection (rr_arity); int adjust = first_arg != NULL_TREE; r->u.arity.expected = expected - adjust; r->u.arity.actual = actual - adjust; + r->u.arity.least_p = least_p; return r; } @@ -3452,6 +3453,44 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, } gcc_assert (ia == nargs_without_in_chrg); + if (!obj && explicit_targs) + { + /* Check that there's no obvious arity mismatch before proceeding with + deduction. This avoids substituting explicit template arguments + into the template (which could result in an error outside the + immediate context) when the resulting candidate would be unviable + anyway. */ + int min_arity = 0, max_arity = 0; + tree parms = TYPE_ARG_TYPES (TREE_TYPE (tmpl)); + parms = skip_artificial_parms_for (tmpl, parms); + for (; parms != void_list_node; parms = TREE_CHAIN (parms)) + { + if (!parms || PACK_EXPANSION_P (TREE_VALUE (parms))) + { + max_arity = -1; + break; + } + if (TREE_PURPOSE (parms)) + /* A parameter with a default argument. */ + ++max_arity; + else + ++min_arity, ++max_arity; + } + if (ia < (unsigned)min_arity) + { + /* Too few arguments. */ + reason = arity_rejection (NULL_TREE, min_arity, ia, + /*least_p=*/(max_arity == -1)); + goto fail; + } + else if (max_arity != -1 && ia > (unsigned)max_arity) + { + /* Too many arguments. */ + reason = arity_rejection (NULL_TREE, max_arity, ia); + goto fail; + } + } + errs = errorcount+sorrycount; if (!obj) convs = alloc_conversions (nargs); @@ -3725,12 +3764,19 @@ print_conversion_rejection (location_t loc, struct conversion_info *info, HAVE. */ static void -print_arity_information (location_t loc, unsigned int have, unsigned int want) -{ - inform_n (loc, want, - " candidate expects %d argument, %d provided", - " candidate expects %d arguments, %d provided", - want, have); +print_arity_information (location_t loc, unsigned int have, unsigned int want, + bool least_p) +{ + if (least_p) + inform_n (loc, want, + " candidate expects at least %d argument, %d provided", + " candidate expects at least %d arguments, %d provided", + want, have); + else + inform_n (loc, want, + " candidate expects %d argument, %d provided", + " candidate expects %d arguments, %d provided", + want, have); } /* Print information about one overload candidate CANDIDATE. MSGSTR @@ -3794,7 +3840,8 @@ print_z_candidate (location_t loc, const char *msgstr, { case rr_arity: print_arity_information (cloc, r->u.arity.actual, - r->u.arity.expected); + r->u.arity.expected, + r->u.arity.least_p); break; case rr_arg_conversion: print_conversion_rejection (cloc, &r->u.conversion, fn); diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype29.C b/gcc/testsuite/g++.dg/cpp0x/decltype29.C index 51da8ddd0ded6a2c1049c6c720a6d21d2889173d..ea97b033569c03d6028983c9b8c1d3a71603253f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/decltype29.C +++ b/gcc/testsuite/g++.dg/cpp0x/decltype29.C @@ -10,10 +10,10 @@ ft() {} template<class F, int N> decltype (ft<F> (F())) // { dg-error "depth" } -ft() {} +ft(F) {} int main() { - ft<struct a*, 0>(); // { dg-message "from here" } + ft<struct a*, 0>(0); // { dg-message "from here" } } // { dg-prune-output "compilation terminated" } diff --git a/gcc/testsuite/g++.dg/template/error56.C b/gcc/testsuite/g++.dg/template/error56.C index e85471a50b09fcb0f3c4d616e034961de3b785f4..71206a1ae5cb7d998d7abaf521983be45e6b033a 100644 --- a/gcc/testsuite/g++.dg/template/error56.C +++ b/gcc/testsuite/g++.dg/template/error56.C @@ -3,12 +3,12 @@ struct A { template <class T> void f(T); - void f(); + void f(int); }; int main() { - A().f<1>(); // { dg-error "f<1>" } + A().f<1>(0); // { dg-error "f<1>" } // { dg-error "type/value mismatch at argument 1" "" { target *-*-* } .-1 } // { dg-message "expected a type, got .1." "" { target *-*-* } .-2 } } diff --git a/gcc/testsuite/g++.dg/template/explicit-args7.C b/gcc/testsuite/g++.dg/template/explicit-args7.C new file mode 100644 index 0000000000000000000000000000000000000000..fb5e89e4cf6074eee7388b5a6d6c49acb6baff22 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args7.C @@ -0,0 +1,33 @@ +// PR c++/12672 +// Verify we don't substitute explicit template arguments into +// candidate function templates when the arity of the function +// template disagrees with the arity of the call. + +template<class T> +struct A { typedef typename T::type type; }; + +template<class T> void f(T); // arity 1 +template<class T> void f(T, T, T); // arity 3 + +template<class T> typename A<T>::type f(T, T); // arity 2 +template<class T, class U> typename A<T>::type f(U, U); // arity 2 + +struct B { + template<class T> void f(T); // arity 1 + template<class T> void f(T, T, T); // arity 3 + + template<class T> typename A<T>::type f(T, T); // arity 2 + template<class T, class U> typename A<T>::type f(U, U); // arity 2 +}; + +int main() { + // If overload resolution attempts deduction for any of the arity-2 function + // templates, the substitution of explicit arguments into the template would + // cause a hard error. + f<int>(1); + f<int>(1, 1, 1); + + B b; + b.f<int>(1); + b.f<int>(1, 1, 1); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C index d122ec2dcb9c7599056a36d092a747e051e86f5e..ee14ceadd915d888f98dabc1181d4f3e38889f18 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C @@ -23,8 +23,8 @@ template<class T> void foo(T const *){} // { dg-error "pointer to reference" } void f() { - foo<int &>(); // { dg-error "" } attempt to build int & const * - foo<void ()>(); // { dg-error "" } attempt to build void (const *)() + foo<int &>(0); // { dg-error "" } attempt to build int & const * + foo<void ()>(0); // OK by [dcl.fct]/7, the const is silently dropped } typedef void (*Fptr)();