C++ PATCH for c++/87378 - bogus -Wredundant-move warning

Jason Merrill jason@redhat.com
Wed Mar 6 16:04:00 GMT 2019


On 3/5/19 4:53 PM, Marek Polacek wrote:
> On Tue, Mar 05, 2019 at 03:50:30PM -0500, Jason Merrill wrote:
>> On 3/4/19 7:17 PM, Marek Polacek wrote:
>>> This patch fixes a bogus -Wredundant-move warning.  In the test in the PR
>>> the std::move call isn't redundant; the testcase won't actually compile
>>> without that call, as per the resolution of bug 87150.
>>>
>>> Before this patch, we'd issue the redundant-move warning anytime
>>> treat_lvalue_as_rvalue_p is true for a std::move's argument.  But we also
>>> need to make sure that convert_for_initialization works even without the
>>> std::move call, if not, it's not redundant.
>>
>> Indeed.
>>
>>> Trouble arises when the argument is const.  Then it might be the case that
>>> the implicit rvalue fails because it uses a const copy constructor, or
>>> that the type of the returned object and the type of the selected ctor's
>>> parameter aren't the same.
>>
>> So this is the case where std::move is redundant because doing overload
>> resolution on the lvalue would select the same constructor?  I'm not sure
>> that's worth warning about, especially in templates where we don't know
>> anything about the return type.
> 
> Yes, it's about:
> 
> struct T {
>    T(const T&);
>    T(T&&);
> };
> 
> T
> f(const T t)
> {
>    return t; // uses const T&
>    return std::move (t); // also uses const T&
> }
> 
> I'm fine with dropping the warning in this (IMO fairly obscure) case; I
> certainly didn't have this in mind when adding the warning.
> 
> So the patch can be simplified to the following:
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?

OK.

> 2019-03-05  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/87378 - bogus -Wredundant-move warning.
> 	* typeck.c (maybe_warn_pessimizing_move): See if the maybe-rvalue
> 	overload resolution would actually succeed.
> 
> 	* g++.dg/cpp0x/Wredundant-move1.C (fn4): Drop dg-warning.
> 	* g++.dg/cpp0x/Wredundant-move7.C: New test.
> 
> diff --git gcc/cp/typeck.c gcc/cp/typeck.c
> index 1bf9ad88141..43ff3d63abd 100644
> --- gcc/cp/typeck.c
> +++ gcc/cp/typeck.c
> @@ -9429,10 +9429,24 @@ maybe_warn_pessimizing_move (tree retval, tree functype)
>   	     do maybe-rvalue overload resolution even without std::move.  */
>   	  else if (treat_lvalue_as_rvalue_p (arg, /*parm_ok*/true))
>   	    {
> -	      auto_diagnostic_group d;
> -	      if (warning_at (loc, OPT_Wredundant_move,
> -			      "redundant move in return statement"))
> -		inform (loc, "remove %<std::move%> call");
> +	      /* Make sure that the overload resolution would actually succeed
> +		 if we removed the std::move call.  */
> +	      tree t = convert_for_initialization (NULL_TREE, functype,
> +						   move (arg),
> +						   (LOOKUP_NORMAL
> +						    | LOOKUP_ONLYCONVERTING
> +						    | LOOKUP_PREFER_RVALUE),
> +						   ICR_RETURN, NULL_TREE, 0,
> +						   tf_none);
> +	      /* If this worked, implicit rvalue would work, so the call to
> +		 std::move is redundant.  */
> +	      if (t != error_mark_node)
> +		{
> +		  auto_diagnostic_group d;
> +		  if (warning_at (loc, OPT_Wredundant_move,
> +				  "redundant move in return statement"))
> +		    inform (loc, "remove %<std::move%> call");
> +		}
>   	    }
>   	}
>       }
> diff --git gcc/testsuite/g++.dg/cpp0x/Wredundant-move1.C gcc/testsuite/g++.dg/cpp0x/Wredundant-move1.C
> index 5d4a25dbc3b..e70f3cde625 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wredundant-move1.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wredundant-move1.C
> @@ -59,7 +59,8 @@ T
>   fn4 (const T t)
>   {
>     // t is const: will decay into copy despite std::move, so it's redundant.
> -  return std::move (t); // { dg-warning "redundant move in return statement" }
> +  // We used to warn about this, but no longer since c++/87378.
> +  return std::move (t);
>   }
>   
>   int
> diff --git gcc/testsuite/g++.dg/cpp0x/Wredundant-move7.C gcc/testsuite/g++.dg/cpp0x/Wredundant-move7.C
> new file mode 100644
> index 00000000000..015d7c4f7a4
> --- /dev/null
> +++ gcc/testsuite/g++.dg/cpp0x/Wredundant-move7.C
> @@ -0,0 +1,59 @@
> +// PR c++/87378
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-Wredundant-move" }
> +
> +// Define std::move.
> +namespace std {
> +  template<typename _Tp>
> +    struct remove_reference
> +    { typedef _Tp   type; };
> +
> +  template<typename _Tp>
> +    struct remove_reference<_Tp&>
> +    { typedef _Tp   type; };
> +
> +  template<typename _Tp>
> +    struct remove_reference<_Tp&&>
> +    { typedef _Tp   type; };
> +
> +  template<typename _Tp>
> +    constexpr typename std::remove_reference<_Tp>::type&&
> +    move(_Tp&& __t) noexcept
> +    { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
> +}
> +
> +struct S1 { S1(S1 &&); };
> +struct S2 : S1 {};
> +
> +S1
> +f (S2 s)
> +{
> +  return std::move(s); // { dg-bogus "redundant move in return statement" }
> +}
> +
> +struct R1 {
> +  R1(R1 &&);
> +  R1(const R1 &&);
> +};
> +struct R2 : R1 {};
> +
> +R1
> +f2 (const R2 s)
> +{
> +  return std::move(s); // { dg-bogus "redundant move in return statement" }
> +}
> +
> +struct T1 {
> +  T1(const T1 &);
> +  T1(T1 &&);
> +  T1(const T1 &&);
> +};
> +struct T2 : T1 {};
> +
> +T1
> +f3 (const T2 s)
> +{
> +  // Without std::move: const T1 &
> +  // With std::move: const T1 &&
> +  return std::move(s); // { dg-bogus "redundant move in return statement" }
> +}
> 



More information about the Gcc-patches mailing list