Skip to content

Commit d9d9301

Browse files
authored
[clang][Sema] Warn on self move for inlined static cast (llvm#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.
1 parent 12fdabc commit d9d9301

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19093,18 +19093,17 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
1909319093
LHSExpr = LHSExpr->IgnoreParenImpCasts();
1909419094
RHSExpr = RHSExpr->IgnoreParenImpCasts();
1909519095

19096-
// Check for a call expression
19097-
const CallExpr *CE = dyn_cast<CallExpr>(RHSExpr);
19098-
if (!CE || CE->getNumArgs() != 1)
19099-
return;
19100-
19101-
// Check for a call to std::move
19102-
if (!CE->isCallToStdMove())
19096+
// Check for a call to std::move or for a static_cast<T&&>(..) to an xvalue
19097+
// which we can treat as an inlined std::move
19098+
if (const auto *CE = dyn_cast<CallExpr>(RHSExpr);
19099+
CE && CE->getNumArgs() == 1 && CE->isCallToStdMove())
19100+
RHSExpr = CE->getArg(0);
19101+
else if (const auto *CXXSCE = dyn_cast<CXXStaticCastExpr>(RHSExpr);
19102+
CXXSCE && CXXSCE->isXValue())
19103+
RHSExpr = CXXSCE->getSubExpr();
19104+
else
1910319105
return;
1910419106

19105-
// Get argument from std::move
19106-
RHSExpr = CE->getArg(0);
19107-
1910819107
const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
1910919108
const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
1911019109

clang/test/SemaCXX/warn-self-move.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ void int_test() {
1616
x = std::move(x); // expected-warning{{explicitly moving}}
1717
(x) = std::move(x); // expected-warning{{explicitly moving}}
1818

19+
x = static_cast<int&&>(x); // expected-warning{{explicitly moving}}
20+
(x) = static_cast<int&&>(x); // expected-warning{{explicitly moving}}
21+
1922
using std::move;
2023
x = move(x); // expected-warning{{explicitly moving}} \
2124
expected-warning {{unqualified call to 'std::move}}
@@ -26,6 +29,9 @@ void global_int_test() {
2629
global = std::move(global); // expected-warning{{explicitly moving}}
2730
(global) = std::move(global); // expected-warning{{explicitly moving}}
2831

32+
global = static_cast<int&&>(global); // expected-warning{{explicitly moving}}
33+
(global) = static_cast<int&&>(global); // expected-warning{{explicitly moving}}
34+
2935
using std::move;
3036
global = move(global); // expected-warning{{explicitly moving}} \
3137
expected-warning {{unqualified call to 'std::move}}
@@ -35,11 +41,16 @@ class field_test {
3541
int x;
3642
field_test(field_test&& other) {
3743
x = std::move(x); // expected-warning{{explicitly moving}}
44+
x = static_cast<int&&>(x); // expected-warning{{explicitly moving}}
3845
x = std::move(other.x);
46+
x = static_cast<int&&>(other.x);
3947
other.x = std::move(x);
48+
other.x = static_cast<int&&>(x);
4049
other.x = std::move(other.x); // expected-warning{{explicitly moving}}
50+
other.x = static_cast<int&&>(other.x); // expected-warning{{explicitly moving}}
4151
}
4252
void withSuggest(int x) {
53+
x = static_cast<int&&>(x); // expected-warning{{explicitly moving variable of type 'int' to itself; did you mean to move to member 'x'?}}
4354
x = std::move(x); // expected-warning{{explicitly moving variable of type 'int' to itself; did you mean to move to member 'x'?}}
4455
}
4556
};
@@ -50,11 +61,15 @@ struct C { C() {}; ~C() {} };
5061
void struct_test() {
5162
A a;
5263
a = std::move(a); // expected-warning{{explicitly moving}}
64+
a = static_cast<A&&>(a); // expected-warning{{explicitly moving}}
5365

5466
B b;
5567
b = std::move(b); // expected-warning{{explicitly moving}}
68+
b = static_cast<B&&>(b); // expected-warning{{explicitly moving}}
5669
b.a = std::move(b.a); // expected-warning{{explicitly moving}}
70+
b.a = static_cast<A&&>(b.a); // expected-warning{{explicitly moving}}
5771

5872
C c;
5973
c = std::move(c); // expected-warning{{explicitly moving}}
74+
c = static_cast<C&&>(c); // expected-warning{{explicitly moving}}
6075
}

0 commit comments

Comments
 (0)