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; +def warn_null_logical_negation_compare : Warning< + "logical negation of %select{address of|function|array}0 '%1' is " + "always %select{true|false}2">, + InGroup; 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; +}