mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 19:44:38 +08:00
Implement -Wself-assign, which warns on code such as:
int x = 42; x = x; // Warns here. The warning avoids macro expansions, templates, user-defined assignment operators, and volatile types, so false positives are expected to be low. The common (mis-)use of this code pattern is to silence unused variable warnings, but a more idiomatic way of doing that is '(void)x;'. A follow-up to this will add a note and fix-it hint suggesting this replacement in cases where the StmtExpr consists precisely of the self assignment. llvm-svn: 122804
This commit is contained in:
@@ -95,6 +95,7 @@ def : DiagGroup<"pointer-to-int-cast">;
|
||||
def : DiagGroup<"redundant-decls">;
|
||||
def ReturnType : DiagGroup<"return-type">;
|
||||
def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">;
|
||||
def SelfAssignment : DiagGroup<"self-assign">;
|
||||
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
|
||||
def : DiagGroup<"sequence-point">;
|
||||
def Shadow : DiagGroup<"shadow">;
|
||||
@@ -216,6 +217,7 @@ def Most : DiagGroup<"most", [
|
||||
MultiChar,
|
||||
Reorder,
|
||||
ReturnType,
|
||||
SelfAssignment,
|
||||
Switch,
|
||||
Trigraphs,
|
||||
Uninitialized,
|
||||
|
||||
@@ -2243,6 +2243,10 @@ def warn_logical_and_in_logical_or : Warning<
|
||||
def note_logical_and_in_logical_or_silence : Note<
|
||||
"place parentheses around the '&&' expression to silence this warning">;
|
||||
|
||||
def warn_self_assignment : Warning<
|
||||
"explicitly assigning a variable of type %0 to itself">,
|
||||
InGroup<SelfAssignment>, DefaultIgnore;
|
||||
|
||||
def err_sizeof_nonfragile_interface : Error<
|
||||
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
|
||||
"non-fragile ABI">;
|
||||
|
||||
@@ -7460,6 +7460,40 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
|
||||
return Opc;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs,
|
||||
SourceLocation OpLoc) {
|
||||
if (!S.ActiveTemplateInstantiations.empty())
|
||||
return;
|
||||
if (OpLoc.isInvalid() || OpLoc.isMacroID())
|
||||
return;
|
||||
lhs = lhs->IgnoreParenImpCasts();
|
||||
rhs = rhs->IgnoreParenImpCasts();
|
||||
const DeclRefExpr *LeftDeclRef = dyn_cast<DeclRefExpr>(lhs);
|
||||
const DeclRefExpr *RightDeclRef = dyn_cast<DeclRefExpr>(rhs);
|
||||
if (!LeftDeclRef || !RightDeclRef ||
|
||||
LeftDeclRef->getLocation().isMacroID() ||
|
||||
RightDeclRef->getLocation().isMacroID())
|
||||
return;
|
||||
const ValueDecl *LeftDecl =
|
||||
cast<ValueDecl>(LeftDeclRef->getDecl()->getCanonicalDecl());
|
||||
const ValueDecl *RightDecl =
|
||||
cast<ValueDecl>(RightDeclRef->getDecl()->getCanonicalDecl());
|
||||
if (LeftDecl != RightDecl)
|
||||
return;
|
||||
if (LeftDecl->getType().isVolatileQualified())
|
||||
return;
|
||||
if (const ReferenceType *RefTy = LeftDecl->getType()->getAs<ReferenceType>())
|
||||
if (RefTy->getPointeeType().isVolatileQualified())
|
||||
return;
|
||||
|
||||
S.Diag(OpLoc, diag::warn_self_assignment)
|
||||
<< LeftDeclRef->getType()
|
||||
<< lhs->getSourceRange() << rhs->getSourceRange();
|
||||
}
|
||||
|
||||
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
|
||||
/// operator @p Opc at location @c TokLoc. This routine only supports
|
||||
/// built-in operations; ActOnBinOp handles overloaded operators.
|
||||
@@ -7482,6 +7516,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
VK = lhs->getValueKind();
|
||||
OK = lhs->getObjectKind();
|
||||
}
|
||||
if (!ResultTy.isNull())
|
||||
DiagnoseSelfAssignment(*this, lhs, rhs, OpLoc);
|
||||
break;
|
||||
case BO_PtrMemD:
|
||||
case BO_PtrMemI:
|
||||
|
||||
47
clang/test/SemaCXX/warn-self-assign.cpp
Normal file
47
clang/test/SemaCXX/warn-self-assign.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -verify %s
|
||||
|
||||
void f() {
|
||||
int a = 42, b = 42;
|
||||
a = a; // expected-warning{{explicitly assigning}}
|
||||
b = b; // expected-warning{{explicitly assigning}}
|
||||
a = b;
|
||||
b = a = b;
|
||||
a = a = a; // expected-warning{{explicitly assigning}}
|
||||
a = b = b = a;
|
||||
}
|
||||
|
||||
// Dummy type.
|
||||
struct S {};
|
||||
|
||||
void false_positives() {
|
||||
#define OP =
|
||||
#define LHS a
|
||||
#define RHS a
|
||||
int a = 42;
|
||||
// These shouldn't warn due to the use of the preprocessor.
|
||||
a OP a;
|
||||
LHS = a;
|
||||
a = RHS;
|
||||
LHS OP RHS;
|
||||
#undef OP
|
||||
#undef LHS
|
||||
#undef RHS
|
||||
|
||||
S s;
|
||||
s = s; // Not a builtin assignment operator, no warning.
|
||||
|
||||
// Volatile stores aren't side-effect free.
|
||||
volatile int vol_a;
|
||||
vol_a = vol_a;
|
||||
volatile int &vol_a_ref = vol_a;
|
||||
vol_a_ref = vol_a_ref;
|
||||
}
|
||||
|
||||
template <typename T> void g() {
|
||||
T a;
|
||||
a = a; // May or may not be a builtin assignment operator, no warning.
|
||||
}
|
||||
void instantiate() {
|
||||
g<int>();
|
||||
g<S>();
|
||||
}
|
||||
Reference in New Issue
Block a user