Message ID | 20180118233521.GP2063@tucnak |
---|---|
State | New |
Headers | show |
Series | [C++] Fix ICE in joust with -Wconversion (PR c++/81167) | expand |
On Thu, Jan 18, 2018 at 6:35 PM, Jakub Jelinek <jakub@redhat.com> wrote: > Hi! > > As mentioned in the PR, we ICE on this testcase because > w->fn is a conversion operator, w->convs[0]->type is a reference > to a class type, but because that conversion is ck_ref_bind, > source_type looks through it and finds ck_identity with > the class type. Then we because w->fn is not a constructor > do source = TREE_TYPE (source);, assuming we got a pointer > type like on the other 5 testcases in check-c++-all with -Wconversion > that cover this code, so source is NULL and we die in calling > warning with bogus arguments. > > The following patch fixes it by only using TREE_TYPE on pointer/reference > types. I must say I don't understand this fully, but conversion > operators should be used on class types, so that is what we are looking for > with source, right? No idea about the ! DECL_CONSTRUCTOR_P (w->fn) > check though and nothing in the testsuite covers that. I think that the test for POINTER_TYPE_P can replace the DECL_CONSTRUCTOR_P test. Jason
--- gcc/cp/call.c.jj 2018-01-17 22:00:13.626228171 +0100 +++ gcc/cp/call.c 2018-01-18 21:01:51.596136303 +0100 @@ -10082,7 +10082,7 @@ joust (struct z_candidate *cand1, struct else if (warn) { tree source = source_type (w->convs[0]); - if (! DECL_CONSTRUCTOR_P (w->fn)) + if (! DECL_CONSTRUCTOR_P (w->fn) && POINTER_TYPE_P (source)) source = TREE_TYPE (source); if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn) && warning (OPT_Wconversion, " for conversion from %qH to %qI", --- gcc/testsuite/g++.dg/cpp0x/pr81167.C.jj 2018-01-18 21:07:48.723189500 +0100 +++ gcc/testsuite/g++.dg/cpp0x/pr81167.C 2018-01-18 21:07:18.610187374 +0100 @@ -0,0 +1,24 @@ +// PR c++/81167 +// { dg-do compile { target c++11 } } +// { dg-options "-Wconversion" } + +struct bar; + +struct foo +{ + foo () {} + foo (const bar &) {} +}; + +struct bar +{ + operator foo () && { return foo (); } +}; + +void test () +{ + foo f = bar (); +// { dg-warning "choosing 'bar::operator foo\\(\\) &&' over 'foo::foo\\(const bar&\\)'" "" { target *-*-* } .-1 } +// { dg-warning "for conversion from 'bar' to 'foo'" "" { target *-*-* } .-2 } +// { dg-message "because conversion sequence for the argument is better" "" { target *-*-* } .-3 } +}