On Wed, 2019-11-20 at 00:38 +0100, Jakub Jelinek wrote: > Hi! > > The following patch is a minimal fix to avoid > cannot convert ‘‘addr_expr’ not supported by dump_type<type error>’ > to ‘X*’ > and similar messages. The recently added complain_about_bad_argument > function expects a from_type argument, but conv->from isn't > necessarily a > type, it can be an expression too. > > With this patch one gets error like: > cannot convert ‘const X*’ to ‘X*’ > and note like > initializing argument 'this' of ‘void X::foo()’ > Still, perhaps what GCC 8 and earlier used to emit might be clearer: > pr90767-1.C: In member function ‘X::operator T() const’: > pr90767-1.C:12:7: error: no matching function for call to ‘X::foo() > const’ > pr90767-1.C:6:8: note: candidate: ‘void X::foo()’ <near match> > pr90767-1.C:6:8: note: passing ‘const X*’ as ‘this’ argument > discards qualifiers > There is the print_conversion_rejection function that handles the > various > cases, like this vs. other arguments, conv->from with expr type vs. > type > etc. > Though, I must say I don't understand the reasons why > complain_about_bad_argument > has been added and whether we'd want to emit there what > print_conversion_rejection prints as notes with 2 leading spaces > instead as > errors with no leading spaces.
I added complain_about_bad_argument in r264250 (aka b78e49d1ddf1a09e16152353b41bf7c0b44d6405); the intent is to special- case when there's a single candidate due to a bad argument, underlining the pertinent bogus argument at the callsite, rather than having the caret at the final close-paren of the call. But it looks like I forgot about the "this" case. Does it make more sense for pr90767-1.C to reject the special-casing if conv->n_arg is -1 for the "this"? (either in complain_about_no_candidates_for_method_call, or in maybe_get_bad_conversion_for_unmatched_call); perhaps like this: diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 0034c1c..eefb7ab 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9855,16 +9855,18 @@ complain_about_no_candidates_for_method_call (tree instance, else { /* Special-case for when there's a single candidate that's failing - due to a bad argument type. */ + due to a bad argument type (but not for the "this" argument), + so that we can underline the pertinent argument at the callsite. */ if (z_candidate *candidate = single_z_candidate (candidates)) if (const conversion_info *conv = maybe_get_bad_conversion_for_unmatched_call (candidate)) - { - complain_about_bad_argument (conv->loc, - conv->from, conv->to_type, - candidate->fn, conv->n_arg); - return; - } + if (conv->n_arg != -1) + { + complain_about_bad_argument (conv->loc, + conv->from, conv->to_type, + candidate->fn, conv->n_arg); + return; + } tree arglist = build_tree_list_vec (user_args); tree errname = name; (caveat: barely tested) Dave > In any case, I think the patch below is a step in the right > direction. > > 2019-11-19 Jakub Jelinek <ja...@redhat.com> > > PR c++/90767 > * call.c (complain_about_no_candidates_for_method_call): If > conv->from is not a type, pass to complain_about_bad_argument > lvalue_type of conv->from. > > * g++.dg/diagnostic/pr90767-1.C: New test. > * g++.dg/diagnostic/pr90767-2.C: New test. > > --- gcc/cp/call.c.jj 2019-11-18 18:49:14.461880924 +0100 > +++ gcc/cp/call.c 2019-11-19 14:40:19.121937148 +0100 > @@ -9861,8 +9861,11 @@ complain_about_no_candidates_for_method_ > if (const conversion_info *conv > = maybe_get_bad_conversion_for_unmatched_call > (candidate)) > { > + tree from_type = conv->from; > + if (!TYPE_P (conv->from)) > + from_type = lvalue_type (conv->from); > complain_about_bad_argument (conv->loc, > - conv->from, conv->to_type, > + from_type, conv->to_type, > candidate->fn, conv->n_arg); > return; > } > --- gcc/testsuite/g++.dg/diagnostic/pr90767-1.C.jj 2019-11-19 > 14:48:00.386041586 +0100 > +++ gcc/testsuite/g++.dg/diagnostic/pr90767-1.C 2019-11-19 > 14:46:53.395043036 +0100 > @@ -0,0 +1,15 @@ > +// PR c++/90767 > +// { dg-do compile } > + > +struct X { > + int n; > + void foo (); // { dg-message "initializing argument 'this'" > } > + > + template<typename T> > + operator T () const > + { > + if (n == 0) > + foo (); // { dg-error "cannot convert 'const X\\*' to 'X\\*'" > } > + return n; > + } > +}; > --- gcc/testsuite/g++.dg/diagnostic/pr90767-2.C.jj 2019-11-19 > 14:50:48.923522136 +0100 > +++ gcc/testsuite/g++.dg/diagnostic/pr90767-2.C 2019-11-19 > 14:52:27.324051149 +0100 > @@ -0,0 +1,15 @@ > +// PR c++/90767 > +// { dg-do compile } > + > +struct A { > + struct B { B (int) {} }; > + > + template <typename T> > + void foo () > + { > + int x = 0; > + bar (x); // { dg-error "cannot convert 'int' to 'A::B&'" } > + } > + > + void bar (B &arg) {} // { dg-message "initializing argument > 1" } > +}; > > Jakub