This patch fixes bogus -Wredundant-move warnings reported in 88692 and 87882.
To quickly recap, this warning is supposed to warn for cases like struct T { }; T fn(T t) { return std::move (t); } where NRVO isn't applicable for T because it's a parameter, but it's a local variable and we're returning, so C++11 says activate move semantics, so the std::move is redundant. But, as these testcases show, we're failing to realize that that is not the case when returning *this, which is disguised as an ordinary PARM_DECL, and treat_lvalue_as_rvalue_p was fooled by that. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-01-07 Marek Polacek <pola...@redhat.com> PR c++/88692, c++/87882 - -Wredundant-move false positive with *this. * typeck.c (treat_lvalue_as_rvalue_p): Return false for 'this'. * g++.dg/cpp0x/Wredundant-move5.C: New test. * g++.dg/cpp0x/Wredundant-move6.C: New test. diff --git gcc/cp/typeck.c gcc/cp/typeck.c index e399cd3fe45..c6908d23a11 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -9371,6 +9371,9 @@ bool treat_lvalue_as_rvalue_p (tree retval, bool parm_ok) { STRIP_ANY_LOCATION_WRAPPER (retval); + /* *this remains an lvalue expression. */ + if (is_this_parameter (retval)) + return false; return ((cxx_dialect != cxx98) && ((VAR_P (retval) && !DECL_HAS_VALUE_EXPR_P (retval)) || (parm_ok && TREE_CODE (retval) == PARM_DECL)) diff --git gcc/testsuite/g++.dg/cpp0x/Wredundant-move5.C gcc/testsuite/g++.dg/cpp0x/Wredundant-move5.C new file mode 100644 index 00000000000..b6a3b2296a8 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/Wredundant-move5.C @@ -0,0 +1,37 @@ +// PR c++/88692 +// { 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 X { + X f() && { + return std::move(*this); // { dg-bogus "redundant move in return statement" } + } + + X f2() & { + return std::move(*this); // { dg-bogus "redundant move in return statement" } + } + + X f3() { + return std::move(*this); // { dg-bogus "redundant move in return statement" } + } +}; diff --git gcc/testsuite/g++.dg/cpp0x/Wredundant-move6.C gcc/testsuite/g++.dg/cpp0x/Wredundant-move6.C new file mode 100644 index 00000000000..5808a78638e --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/Wredundant-move6.C @@ -0,0 +1,43 @@ +// PR c++/87882 +// { 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 Foo { + Foo Bar() { + return std::move(*this); // { dg-bogus "redundant move in return statement" } + } + Foo Baz() { + return *this; + } + int i; +}; + +void Move(Foo & f) +{ + f = Foo{}.Bar(); +} + +void NoMove(Foo & f) +{ + f = Foo{}.Baz(); +}