diff options
author | Richard Trieu <rtrieu@google.com> | 2015-01-10 06:04:18 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2015-01-10 06:04:18 +0000 |
commit | 53472c9fc35126a8473db35e8ea8daabadf761b4 (patch) | |
tree | 499b0b47f53f471ccb07705143dc7ea801b0c6a2 /lib/Sema/SemaExpr.cpp | |
parent | 22c634704f7f4a0803f08bebd1e1bc662f5ab77f (diff) |
Add a new warning, -Wself-move, to Clang.
-Wself-move is similiar to -Wself-assign. This warning is triggered when
a value is attempted to be moved to itself. See r221008 for a bug that
would have been caught with this warning.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@225581 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 68bad16ff3..c912520983 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9380,6 +9380,90 @@ 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. @@ -9507,8 +9591,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, VK = LHS.get()->getValueKind(); OK = LHS.get()->getObjectKind(); } - if (!ResultTy.isNull()) + if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); + DiagnoseSelfMove(*this, LHS.get(), RHS.get(), OpLoc); + } RecordModifiableNonNullParam(*this, LHS.get()); break; case BO_PtrMemD: |