diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 90 |
1 files changed, 90 insertions, 0 deletions
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 { |