Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h (revision 221791) +++ include/clang/Sema/Sema.h (working copy) @@ -2982,6 +2982,7 @@ return TypoCorrection(); } + void CheckBoolLikeConversion(Expr *E, SourceLocation CC); public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp (revision 221791) +++ lib/Sema/SemaChecking.cpp (working copy) @@ -6480,6 +6480,13 @@ E->getType(), CC, &Suspicious); } +static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { + if (S.getLangOpts().Bool) + return; + CheckImplicitConversion(S, E->IgnoreParenImpCasts(), + S.Context.BoolTy, CC); +} + /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. @@ -6532,6 +6539,11 @@ // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); + + if (BO->isLogicalOp()) { + CheckBoolLikeConversion(S, BO->getLHS(), BO->getLHS()->getExprLoc()); + CheckBoolLikeConversion(S, BO->getRHS(), BO->getRHS()->getExprLoc()); + } } // These break the otherwise-useful invariant below. Fortunately, @@ -6559,6 +6571,9 @@ continue; AnalyzeImplicitConversions(S, ChildExpr, CC); } + if (const UnaryOperator *U = dyn_cast(E)) + if (U->getOpcode() == UO_LNot) + CheckBoolLikeConversion(S, U->getSubExpr(), CC); } } // end anonymous namespace @@ -6617,6 +6632,10 @@ return false; } +void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { + ::CheckBoolLikeConversion(*this, E, CC); +} + /// \brief Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp (revision 221791) +++ lib/Sema/SemaExpr.cpp (working copy) @@ -8413,7 +8413,7 @@ if (!LHS.get()->getType()->isScalarType() || !RHS.get()->getType()->isScalarType()) return InvalidOperands(Loc, LHS, RHS); - + return Context.IntTy; } @@ -12982,6 +12982,7 @@ << T << E->getSourceRange(); return ExprError(); } + CheckBoolLikeConversion(E, Loc); } return E; Index: test/Analysis/NSContainers.m =================================================================== --- test/Analysis/NSContainers.m (revision 221791) +++ test/Analysis/NSContainers.m (working copy) @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s void clang_analyzer_eval(int); Index: test/Analysis/logical-ops.c =================================================================== --- test/Analysis/logical-ops.c (revision 221791) +++ test/Analysis/logical-ops.c (working copy) @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s +// RUN: %clang_cc1 -Wno-pointer-bool-conversion -analyze -analyzer-checker=core,debug.ExprInspection -verify %s void clang_analyzer_eval(int); Index: test/Analysis/objc-boxing.m =================================================================== --- test/Analysis/objc-boxing.m (revision 221791) +++ test/Analysis/objc-boxing.m (working copy) @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_cc1 -Wno-objc-literal-conversion -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s void clang_analyzer_eval(int); Index: test/Sema/exprs.c =================================================================== --- test/Sema/exprs.c (revision 221791) +++ test/Sema/exprs.c (working copy) @@ -244,6 +244,10 @@ if ("help") (void) 0; - if (test22) + if (test22) // expected-warning {{address of function 'test22' will always evaluate to 'true'}} \ + // expected-note {{prefix with the address-of operator to silence this warning}} (void) 0; + + if (&test22) + (void) 0; } 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,80 @@ +// 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 {{address of array 'b' will always evaluate to 'true'}} + if (b == 0) {} // expected-warning {{comparison of array 'b' equal to a null pointer is always false}} + if (!c.x) {} // expected-warning {{address of array 'c.x' will always evaluate to 'true'}} + if (c.x == 0) {} // expected-warning {{comparison of array 'c.x' equal to a null pointer is always false}} + if (!str) {} // expected-warning {{address of array 'str' will always evaluate to 'true'}} + 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 {{address of array 'array' will always evaluate to 'true'}} + 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; +} + +#define NULL (void*)0 + +int test2(int* pointer, char ch, void * pv) { + if (!&pointer) { // expected-warning {{address of 'pointer' will always evaluate to 'true'}} + return 0; + } + + if (&pointer) { // expected-warning {{address of 'pointer' will always evaluate to 'true'}} + return 0; + } + + if (&pointer == NULL) {} // expected-warning {{comparison of address of 'pointer' equal to a null pointer is always false}} + + if (&pointer != NULL) {} // expected-warning {{comparison of address of 'pointer' not equal to a null pointer is always true}} + + return 1; +} + +void test3() { + if (array) { } // expected-warning {{address of array 'array' will always evaluate to 'true'}} + if (array != 0) {} // expected-warning {{comparison of array 'array' not equal to a null pointer is always true}} + if (!array) { } // expected-warning {{address of array 'array' will always evaluate to 'true'}} + if (array == 0) {} // expected-warning {{comparison of array 'array' equal to a null pointer is always false}} + + if (array[0] && + array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}} + + if (array[0] || + array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}} + + if (array[0] && + !array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}} + if (array[0] || + !array) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}} + + if (array && // expected-warning {{address of array 'array' will always evaluate to 'true'}} + array[0]) {} + if (!array || // expected-warning {{address of array 'array' will always evaluate to 'true'}} + array[0]) {} + + if (array || // expected-warning {{address of array 'array' will always evaluate to 'true'}} + (!array && array[0])) {} // expected-warning {{address of array 'array' will always evaluate to 'true'}} + } + +