diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2a69325f02951..c3f2650113f6c 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -18843,18 +18843,17 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, LHSExpr = LHSExpr->IgnoreParenImpCasts(); RHSExpr = RHSExpr->IgnoreParenImpCasts(); - // Check for a call expression - const CallExpr *CE = dyn_cast(RHSExpr); - if (!CE || CE->getNumArgs() != 1) - return; - - // Check for a call to std::move - if (!CE->isCallToStdMove()) + // Check for a call to std::move or for a static_cast(..) to an xvalue + // which we can treat as an inlined std::move + if (const auto *CE = dyn_cast(RHSExpr); + CE && CE->getNumArgs() == 1 && CE->isCallToStdMove()) + RHSExpr = CE->getArg(0); + else if (const auto *CXXSCE = dyn_cast(RHSExpr); + CXXSCE && CXXSCE->isXValue()) + RHSExpr = CXXSCE->getSubExpr(); + else return; - // Get argument from std::move - RHSExpr = CE->getArg(0); - const DeclRefExpr *LHSDeclRef = dyn_cast(LHSExpr); const DeclRefExpr *RHSDeclRef = dyn_cast(RHSExpr); diff --git a/clang/test/SemaCXX/warn-self-move.cpp b/clang/test/SemaCXX/warn-self-move.cpp index 0987e9b6bf601..5937bb705ed22 100644 --- a/clang/test/SemaCXX/warn-self-move.cpp +++ b/clang/test/SemaCXX/warn-self-move.cpp @@ -16,6 +16,9 @@ void int_test() { x = std::move(x); // expected-warning{{explicitly moving}} (x) = std::move(x); // expected-warning{{explicitly moving}} + x = static_cast(x); // expected-warning{{explicitly moving}} + (x) = static_cast(x); // expected-warning{{explicitly moving}} + using std::move; x = move(x); // expected-warning{{explicitly moving}} \ expected-warning {{unqualified call to 'std::move}} @@ -26,6 +29,9 @@ void global_int_test() { global = std::move(global); // expected-warning{{explicitly moving}} (global) = std::move(global); // expected-warning{{explicitly moving}} + global = static_cast(global); // expected-warning{{explicitly moving}} + (global) = static_cast(global); // expected-warning{{explicitly moving}} + using std::move; global = move(global); // expected-warning{{explicitly moving}} \ expected-warning {{unqualified call to 'std::move}} @@ -35,11 +41,16 @@ class field_test { int x; field_test(field_test&& other) { x = std::move(x); // expected-warning{{explicitly moving}} + x = static_cast(x); // expected-warning{{explicitly moving}} x = std::move(other.x); + x = static_cast(other.x); other.x = std::move(x); + other.x = static_cast(x); other.x = std::move(other.x); // expected-warning{{explicitly moving}} + other.x = static_cast(other.x); // expected-warning{{explicitly moving}} } void withSuggest(int x) { + x = static_cast(x); // expected-warning{{explicitly moving variable of type 'int' to itself; did you mean to move to member 'x'?}} x = std::move(x); // expected-warning{{explicitly moving variable of type 'int' to itself; did you mean to move to member 'x'?}} } }; @@ -50,11 +61,15 @@ struct C { C() {}; ~C() {} }; void struct_test() { A a; a = std::move(a); // expected-warning{{explicitly moving}} + a = static_cast(a); // expected-warning{{explicitly moving}} B b; b = std::move(b); // expected-warning{{explicitly moving}} + b = static_cast(b); // expected-warning{{explicitly moving}} b.a = std::move(b.a); // expected-warning{{explicitly moving}} + b.a = static_cast(b.a); // expected-warning{{explicitly moving}} C c; c = std::move(c); // expected-warning{{explicitly moving}} + c = static_cast(c); // expected-warning{{explicitly moving}} }