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:
Chandler Carruth
2011-01-04 06:52:15 +00:00
parent 82e8332a22
commit e0cee6a8b0
4 changed files with 89 additions and 0 deletions

View File

@@ -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,

View File

@@ -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">;

View File

@@ -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:

View 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>();
}