[clang] d9d9301 - [clang][Sema] Warn on self move for inlined static cast (#76646)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 6 07:58:16 PST 2024


Author: Max Winkler
Date: 2024-03-06T16:58:12+01:00
New Revision: d9d9301eec6dfefcf53fd04b61324f140f273033

URL: https://github.com/llvm/llvm-project/commit/d9d9301eec6dfefcf53fd04b61324f140f273033
DIFF: https://github.com/llvm/llvm-project/commit/d9d9301eec6dfefcf53fd04b61324f140f273033.diff

LOG: [clang][Sema] Warn on self move for inlined static cast (#76646)

There are code bases that inline `std::move` manually via `static_cast`.
Treat a static cast to an xvalue as an inlined `std::move` call and warn
on a self move.

Added: 
    

Modified: 
    clang/lib/Sema/SemaChecking.cpp
    clang/test/SemaCXX/warn-self-move.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6ed61a19ff17dd..3597f93a017136 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19093,18 +19093,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<CallExpr>(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<T&&>(..) to an xvalue
+  // which we can treat as an inlined std::move
+  if (const auto *CE = dyn_cast<CallExpr>(RHSExpr);
+      CE && CE->getNumArgs() == 1 && CE->isCallToStdMove())
+    RHSExpr = CE->getArg(0);
+  else if (const auto *CXXSCE = dyn_cast<CXXStaticCastExpr>(RHSExpr);
+           CXXSCE && CXXSCE->isXValue())
+    RHSExpr = CXXSCE->getSubExpr();
+  else
     return;
 
-  // Get argument from std::move
-  RHSExpr = CE->getArg(0);
-
   const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
   const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
 

diff  --git a/clang/test/SemaCXX/warn-self-move.cpp b/clang/test/SemaCXX/warn-self-move.cpp
index 0987e9b6bf6017..5937bb705ed227 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<int&&>(x);  // expected-warning{{explicitly moving}}
+  (x) = static_cast<int&&>(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<int&&>(global);  // expected-warning{{explicitly moving}}
+  (global) = static_cast<int&&>(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<int&&>(x);  // expected-warning{{explicitly moving}}
     x = std::move(other.x);
+    x = static_cast<int&&>(other.x);
     other.x = std::move(x);
+    other.x = static_cast<int&&>(x);
     other.x = std::move(other.x);  // expected-warning{{explicitly moving}}
+    other.x = static_cast<int&&>(other.x);  // expected-warning{{explicitly moving}}
   }
   void withSuggest(int x) {
+    x = static_cast<int&&>(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&&>(a);  // expected-warning{{explicitly moving}}
 
   B b;
   b = std::move(b);  // expected-warning{{explicitly moving}}
+  b = static_cast<B&&>(b);  // expected-warning{{explicitly moving}}
   b.a = std::move(b.a);  // expected-warning{{explicitly moving}}
+  b.a = static_cast<A&&>(b.a);  // expected-warning{{explicitly moving}}
 
   C c;
   c = std::move(c);  // expected-warning{{explicitly moving}}
+  c = static_cast<C&&>(c);  // expected-warning{{explicitly moving}}
 }


        


More information about the cfe-commits mailing list