I would like to warn on logical negation of operands with known non-null value; 
as in "if (!array)…", just as we warn on "if (array == 0)…"
Note that this is a c-only patch. c++ already has a warning when such non-null 
pointers are implicitly converted to bool. 
Is this ok for check-in?

- Fariborz

Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h    (revision 220486)
+++ include/clang/AST/Expr.h    (working copy)
@@ -641,7 +641,10 @@
     NPCK_CXX11_nullptr,
 
     /// \brief Expression is a GNU-style __null constant.
-    NPCK_GNUNull
+    NPCK_GNUNull,
+    
+    /// \brief Expression is operand of a logical negation operator
+    NPCK_LNEG_ZeroLiteral
   };
 
   /// \brief Enumeration used to describe how \c isNullPointerConstant()
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td  (revision 220486)
+++ include/clang/Basic/DiagnosticSemaKinds.td  (working copy)
@@ -2512,6 +2512,10 @@
     "comparison of %select{address of|function|array}0 '%1' %select{not |}2"
     "equal to a null pointer is always %select{true|false}2">,
     InGroup<TautologicalPointerCompare>;
+def warn_null_logical_negation_compare : Warning<
+    "logical negation of %select{address of|function|array}0 '%1' is "
+    "always %select{true|false}2">,
+    InGroup<TautologicalPointerCompare>;
 def warn_this_null_compare : Warning<
   "'this' pointer cannot be null in well-defined C++ code; comparison may be "
   "assumed to always evaluate to %select{true|false}0">,
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp   (revision 220486)
+++ lib/Sema/SemaChecking.cpp   (working copy)
@@ -6697,8 +6697,11 @@
   llvm::raw_string_ostream S(Str);
   E->printPretty(S, nullptr, getPrintingPolicy());
 
-  unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
-                              : diag::warn_impcast_pointer_to_bool;
+  unsigned DiagID =
+    IsCompare ? (NullKind != Expr::NPCK_LNEG_ZeroLiteral
+                 ? diag::warn_null_pointer_compare
+                 : diag::warn_null_logical_negation_compare)
+              : diag::warn_impcast_pointer_to_bool;
   unsigned DiagType;
   if (IsAddressOf)
     DiagType = AddressOf;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp       (revision 220486)
+++ lib/Sema/SemaExpr.cpp       (working copy)
@@ -9952,7 +9952,10 @@
   // that are explicitly defined as valid by the standard).
   if (Opc != UO_AddrOf && Opc != UO_Deref)
     CheckArrayAccess(Input.get());
-
+  if (Opc == UO_LNot && Input.get()->getType()->isPointerType() &&
+      !getLangOpts().CPlusPlus)
+    DiagnoseAlwaysNonNullPointer(Input.get(), Expr::NPCK_LNEG_ZeroLiteral,
+                                 true, SourceRange());
   return new (Context)
       UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc);
 }
Index: test/Sema/warn-tautological-compare.c
===================================================================
--- test/Sema/warn-tautological-compare.c       (revision 0)
+++ test/Sema/warn-tautological-compare.c       (working copy)
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -verify  %s
+// rdar://18716393
+
+extern int a[] __attribute__((weak));
+int b[] = {8,13,21};
+struct {
+  int x[10];
+} c;
+const char str[] = "text";
+
+void ignore() {
+  if (!a) {}
+}
+void test() {
+  if (!b) {} // expected-warning {{logical negation of array 'b' is always 
false}}
+  if (b == 0) {} // expected-warning {{comparison of array 'b' equal to a null 
pointer is always false}}
+  if (!c.x) {} // expected-warning {{logical negation of array 'c.x' is always 
false}}
+  if (c.x == 0) {} // expected-warning {{comparison of array 'c.x' equal to a 
null pointer is always false}}
+  if (!str) {} // expected-warning {{logical negation of array 'str' is always 
false}}
+  if (0 == str) {} // expected-warning {{comparison of array 'str' equal to a 
null pointer is always false}}
+}
+
+int array[2];
+int test1()
+{
+  if (!array) { // expected-warning {{logical negation of array 'array' is 
always false}}
+    return array[0];
+  } else if (array != 0) { // expected-warning {{comparison of array 'array' 
not equal to a null pointer is always true}}
+    return array[1];
+  }
+  if (array == 0) // expected-warning {{comparison of array 'array' equal to a 
null pointer is always false}}
+    return 1;
+  return 0;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to