[cfe-commits] r122804 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/SemaCXX/warn-self-assign.cpp

Chandler Carruth chandlerc at gmail.com
Mon Jan 3 22:52:15 PST 2011


Author: chandlerc
Date: Tue Jan  4 00:52:15 2011
New Revision: 122804

URL: http://llvm.org/viewvc/llvm-project?rev=122804&view=rev
Log:
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.

Added:
    cfe/trunk/test/SemaCXX/warn-self-assign.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=122804&r1=122803&r2=122804&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Jan  4 00:52:15 2011
@@ -95,6 +95,7 @@
 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 @@
     MultiChar,
     Reorder,
     ReturnType,
+    SelfAssignment,
     Switch,
     Trigraphs,
     Uninitialized,

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=122804&r1=122803&r2=122804&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan  4 00:52:15 2011
@@ -2243,6 +2243,10 @@
 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">;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=122804&r1=122803&r2=122804&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jan  4 00:52:15 2011
@@ -7460,6 +7460,40 @@
   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 @@
       VK = lhs->getValueKind();
       OK = lhs->getObjectKind();
     }
+    if (!ResultTy.isNull())
+      DiagnoseSelfAssignment(*this, lhs, rhs, OpLoc);
     break;
   case BO_PtrMemD:
   case BO_PtrMemI:

Added: cfe/trunk/test/SemaCXX/warn-self-assign.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-self-assign.cpp?rev=122804&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-self-assign.cpp (added)
+++ cfe/trunk/test/SemaCXX/warn-self-assign.cpp Tue Jan  4 00:52:15 2011
@@ -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>();
+}





More information about the cfe-commits mailing list