diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 90 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 86 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 7 | ||||
-rw-r--r-- | clang/test/SemaCXX/warn-self-move.cpp | 15 |
5 files changed, 116 insertions, 86 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 95fc68fbc13..2ba74b12f6f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3326,6 +3326,10 @@ public: void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); + /// Warn if a value is moved to itself. + void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, + SourceLocation OpLoc); + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index d14549c9e8c..9fc2bec23b1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8325,6 +8325,96 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, } } +//===--- CHECK: Warn on self move with std::move. -------------------------===// + +/// DiagnoseSelfMove - Emits a warning if a value is moved to itself. +void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, + SourceLocation OpLoc) { + + if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) + return; + + if (!ActiveTemplateInstantiations.empty()) + return; + + // Strip parens and casts away. + 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 + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || + !FD->getIdentifier()->isStr("move")) + return; + + // Get argument from std::move + RHSExpr = CE->getArg(0); + + const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); + const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); + + // Two DeclRefExpr's, check that the decls are the same. + if (LHSDeclRef && RHSDeclRef) { + if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) + return; + if (LHSDeclRef->getDecl()->getCanonicalDecl() != + RHSDeclRef->getDecl()->getCanonicalDecl()) + return; + + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + return; + } + + // Member variables require a different approach to check for self moves. + // MemberExpr's are the same if every nested MemberExpr refers to the same + // Decl and that the base Expr's are DeclRefExpr's with the same Decl or + // the base Expr's are CXXThisExpr's. + const Expr *LHSBase = LHSExpr; + const Expr *RHSBase = RHSExpr; + const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr); + const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr); + if (!LHSME || !RHSME) + return; + + while (LHSME && RHSME) { + if (LHSME->getMemberDecl()->getCanonicalDecl() != + RHSME->getMemberDecl()->getCanonicalDecl()) + return; + + LHSBase = LHSME->getBase(); + RHSBase = RHSME->getBase(); + LHSME = dyn_cast<MemberExpr>(LHSBase); + RHSME = dyn_cast<MemberExpr>(RHSBase); + } + + LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase); + RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase); + if (LHSDeclRef && RHSDeclRef) { + if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) + return; + if (LHSDeclRef->getDecl()->getCanonicalDecl() != + RHSDeclRef->getDecl()->getCanonicalDecl()) + return; + + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + return; + } + + if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); +} + //===--- Layout compatibility ----------------------------------------------// namespace { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index cd953ab8986..59efbc1bb6a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9380,90 +9380,6 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( return Opc; } -/// DiagnoseSelfMove - Emits a warning if a value is moved to itself. -static void DiagnoseSelfMove(Sema &S, const Expr *LHSExpr, const Expr *RHSExpr, - SourceLocation OpLoc) { - if (!S.ActiveTemplateInstantiations.empty()) - return; - - // Strip parens and casts away. - 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 - const FunctionDecl *FD = CE->getDirectCallee(); - if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || - !FD->getIdentifier()->isStr("move")) - return; - - // Get argument from std::move - RHSExpr = CE->getArg(0); - - const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); - const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); - - // Two DeclRefExpr's, check that the decls are the same. - if (LHSDeclRef && RHSDeclRef) { - if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) - return; - if (LHSDeclRef->getDecl()->getCanonicalDecl() != - RHSDeclRef->getDecl()->getCanonicalDecl()) - return; - - S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); - return; - } - - // Member variables require a different approach to check for self moves. - // MemberExpr's are the same if every nested MemberExpr refers to the same - // Decl and that the base Expr's are DeclRefExpr's with the same Decl or - // the base Expr's are CXXThisExpr's. - const Expr *LHSBase = LHSExpr; - const Expr *RHSBase = RHSExpr; - const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr); - const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr); - if (!LHSME || !RHSME) - return; - - while (LHSME && RHSME) { - if (LHSME->getMemberDecl()->getCanonicalDecl() != - RHSME->getMemberDecl()->getCanonicalDecl()) - return; - - LHSBase = LHSME->getBase(); - RHSBase = RHSME->getBase(); - LHSME = dyn_cast<MemberExpr>(LHSBase); - RHSME = dyn_cast<MemberExpr>(RHSBase); - } - - LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase); - RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase); - if (LHSDeclRef && RHSDeclRef) { - if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) - return; - if (LHSDeclRef->getDecl()->getCanonicalDecl() != - RHSDeclRef->getDecl()->getCanonicalDecl()) - return; - - S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); - return; - } - - if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) - S.Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); -} - /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. /// This warning is only emitted for builtin assignment operations. It is also /// suppressed in the event of macro expansions. @@ -9593,7 +9509,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); - DiagnoseSelfMove(*this, LHS.get(), RHS.get(), OpLoc); + DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); } RecordModifiableNonNullParam(*this, LHS.get()); break; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8341c008e82..9195ee59075 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11199,7 +11199,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Cut off the implicit 'this'. if (isa<CXXMethodDecl>(FnDecl)) ArgsArray = ArgsArray.slice(1); - checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc, + + // Check for a self move. + if (Op == OO_Equal) + DiagnoseSelfMove(Args[0], Args[1], OpLoc); + + checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(), VariadicDoesNotApply); return MaybeBindToTemporary(TheCall); diff --git a/clang/test/SemaCXX/warn-self-move.cpp b/clang/test/SemaCXX/warn-self-move.cpp index ae2dab1de10..23778c18711 100644 --- a/clang/test/SemaCXX/warn-self-move.cpp +++ b/clang/test/SemaCXX/warn-self-move.cpp @@ -38,3 +38,18 @@ class field_test { other.x = std::move(other.x); // expected-warning{{explicitly moving}} } }; + +struct A {}; +struct B { A a; }; +struct C { C() {}; ~C() {} }; +void struct_test() { + A a; + a = std::move(a); // expected-warning{{explicitly moving}} + + B b; + b = std::move(b); // expected-warning{{explicitly moving}} + b.a = std::move(b.a); // expected-warning{{explicitly moving}} + + C c; + c = std::move(c); // expected-warning{{explicitly moving}} +} |