https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77733

David Malcolm <dmalcolm at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |dmalcolm at gcc dot gnu.org

--- Comment #3 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #2)
> The location for the "cannot bind rvalue reference" error is not a rich
> location, so I couldn't figure out how to add a proper fix-it.

It's trivial to get a rich_location from a location_t:

   rich_location richloc (loc);
   // maybe add some fixits to richloc here...
   error_at_rich_loc (&richloc, "cannot bind..." etc etc

An issue here is that "loc" isn't a good enough location_t: in
convert_like_real it comes from:

  location_t loc = EXPR_LOC_OR_LOC (expr, input_location);

In the example, expr is a VAR_DECL and uses of decls don't have locations, so
it uses input_location for "loc", putting it on the closing paren of the call:

/tmp/test.cc: In function ‘int main()’:
/tmp/test.cc:14:10: error: cannot bind rvalue reference of type ‘X&&’ to lvalue
of type ‘X’
   y.foo(x);
          ^

If loc had a meaningful location for x, you could use something like,:
  richloc.add_fixit_insert_before (loc, "std::move (");
  richloc.add_fixit_insert_after (loc, ")");

The "not every expression has a location_t" is PR 43486 - maybe this should be
a dependency of that bug? (unless there's some way to ensure that all callers
of convert_like_real preserve the location information from the cp_expr in the
C++ parser).

(I've been experimenting with ideas for fixing PR 43486, but it's unlikely to
make it for gcc 7).

> This just adds "did you mean std::move(x)?" to the end:
> 
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -6804,7 +6804,8 @@ convert_like_real (conversion *convs, tree expr, tree
> fn, int argnum,
>             if (TYPE_REF_IS_RVALUE (ref_type)
>                 && lvalue_p (expr))
>               error_at (loc, "cannot bind rvalue reference of type %qT to "
> -                        "lvalue of type %qT", totype, extype);
> +                        "lvalue of type %qT; did you mean
> %<std::move(%E)%>?",
> +                        totype, extype, expr);
>             else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
>                      && !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
>               error_at (loc, "cannot bind non-const lvalue reference of "

FWIW, I'm not sure we want to add uses of %E to the compiler; my recollection
is that it can lead to poor output for the more complicated cases.

> Of course sometimes std::move is not the right fix, and it should be
> std::forward<something>(x) instead. Maybe it would be possible to detect
> whether the expression is a function parameter declared as a forwarding
> reference, but that's probably beyond my ken.
> Also, if the lvalue is cv-qualified this still suggests std::move(x) even
> when that wouldn't work:
> 
> move2.cc:13:9: error: cannot bind rvalue reference of type ‘X&&’ to lvalue
> of type ‘const X’; did you mean ‘std::move(x)’? 
> 
> 
> There's room for improvement.

(nods)

Reply via email to