forked from OSchip/llvm-project
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. llvm-svn: 225581
This commit is contained in:
parent
cbc7ae25da
commit
17ddb829aa
|
@ -294,6 +294,7 @@ def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",
|
||||||
[CXX98CompatBindToTemporaryCopy]>;
|
[CXX98CompatBindToTemporaryCopy]>;
|
||||||
def SelfAssignmentField : DiagGroup<"self-assign-field">;
|
def SelfAssignmentField : DiagGroup<"self-assign-field">;
|
||||||
def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>;
|
def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>;
|
||||||
|
def SelfMove : DiagGroup<"self-move">;
|
||||||
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
|
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
|
||||||
def Sentinel : DiagGroup<"sentinel">;
|
def Sentinel : DiagGroup<"sentinel">;
|
||||||
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
|
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
|
||||||
|
@ -586,6 +587,7 @@ def Most : DiagGroup<"most", [
|
||||||
Reorder,
|
Reorder,
|
||||||
ReturnType,
|
ReturnType,
|
||||||
SelfAssignment,
|
SelfAssignment,
|
||||||
|
SelfMove,
|
||||||
SizeofArrayArgument,
|
SizeofArrayArgument,
|
||||||
SizeofArrayDecay,
|
SizeofArrayDecay,
|
||||||
StringPlusInt,
|
StringPlusInt,
|
||||||
|
|
|
@ -4701,6 +4701,9 @@ def warn_addition_in_bitshift : Warning<
|
||||||
def warn_self_assignment : Warning<
|
def warn_self_assignment : Warning<
|
||||||
"explicitly assigning value of variable of type %0 to itself">,
|
"explicitly assigning value of variable of type %0 to itself">,
|
||||||
InGroup<SelfAssignment>, DefaultIgnore;
|
InGroup<SelfAssignment>, DefaultIgnore;
|
||||||
|
def warn_self_move : Warning<
|
||||||
|
"explicitly moving variable of type %0 to itself">,
|
||||||
|
InGroup<SelfMove>, DefaultIgnore;
|
||||||
|
|
||||||
def warn_string_plus_int : Warning<
|
def warn_string_plus_int : Warning<
|
||||||
"adding %0 to a string does not append to the string">,
|
"adding %0 to a string does not append to the string">,
|
||||||
|
|
|
@ -9380,6 +9380,90 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
|
||||||
return Opc;
|
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.
|
/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.
|
||||||
/// This warning is only emitted for builtin assignment operations. It is also
|
/// This warning is only emitted for builtin assignment operations. It is also
|
||||||
/// suppressed in the event of macro expansions.
|
/// suppressed in the event of macro expansions.
|
||||||
|
@ -9507,8 +9591,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||||
VK = LHS.get()->getValueKind();
|
VK = LHS.get()->getValueKind();
|
||||||
OK = LHS.get()->getObjectKind();
|
OK = LHS.get()->getObjectKind();
|
||||||
}
|
}
|
||||||
if (!ResultTy.isNull())
|
if (!ResultTy.isNull()) {
|
||||||
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
|
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
|
||||||
|
DiagnoseSelfMove(*this, LHS.get(), RHS.get(), OpLoc);
|
||||||
|
}
|
||||||
RecordModifiableNonNullParam(*this, LHS.get());
|
RecordModifiableNonNullParam(*this, LHS.get());
|
||||||
break;
|
break;
|
||||||
case BO_PtrMemD:
|
case BO_PtrMemD:
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -Wself-move -std=c++11 -verify %s
|
||||||
|
|
||||||
|
// definitions for std::move
|
||||||
|
namespace std {
|
||||||
|
inline namespace foo {
|
||||||
|
template <class T> struct remove_reference { typedef T type; };
|
||||||
|
template <class T> struct remove_reference<T&> { typedef T type; };
|
||||||
|
template <class T> struct remove_reference<T&&> { typedef T type; };
|
||||||
|
|
||||||
|
template <class T> typename remove_reference<T>::type &&move(T &&t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void int_test() {
|
||||||
|
int x = 5;
|
||||||
|
x = std::move(x); // expected-warning{{explicitly moving}}
|
||||||
|
(x) = std::move(x); // expected-warning{{explicitly moving}}
|
||||||
|
|
||||||
|
using std::move;
|
||||||
|
x = move(x); // expected-warning{{explicitly moving}}
|
||||||
|
}
|
||||||
|
|
||||||
|
int global;
|
||||||
|
void global_int_test() {
|
||||||
|
global = std::move(global); // expected-warning{{explicitly moving}}
|
||||||
|
(global) = std::move(global); // expected-warning{{explicitly moving}}
|
||||||
|
|
||||||
|
using std::move;
|
||||||
|
global = move(global); // expected-warning{{explicitly moving}}
|
||||||
|
}
|
||||||
|
|
||||||
|
class field_test {
|
||||||
|
int x;
|
||||||
|
field_test(field_test&& other) {
|
||||||
|
x = std::move(x); // expected-warning{{explicitly moving}}
|
||||||
|
x = std::move(other.x);
|
||||||
|
other.x = std::move(x);
|
||||||
|
other.x = std::move(other.x); // expected-warning{{explicitly moving}}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue