diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2014-11-14 17:12:50 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2014-11-14 17:12:50 +0000 |
commit | b7859ddf9bdc2b8ef689036fadb4501cf22d79f4 (patch) | |
tree | 520645c32bb4333a17b241f5700b6dc15959556d /clang | |
parent | df8f2a23cbaf0ff16cdc9d98fba10dc2b323985c (diff) | |
download | bcm5719-llvm-b7859ddf9bdc2b8ef689036fadb4501cf22d79f4.tar.gz bcm5719-llvm-b7859ddf9bdc2b8ef689036fadb4501cf22d79f4.zip |
[Sema]. Warn when logical expression is a pointer
which evaluates to true. rdar://18716393.
Reviewed by Richard Trieu
llvm-svn: 222009
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 1 | ||||
-rw-r--r-- | clang/test/Analysis/NSContainers.m | 2 | ||||
-rw-r--r-- | clang/test/Analysis/logical-ops.c | 2 | ||||
-rw-r--r-- | clang/test/Analysis/objc-boxing.m | 2 | ||||
-rw-r--r-- | clang/test/Sema/exprs.c | 6 | ||||
-rw-r--r-- | clang/test/Sema/warn-tautological-compare.c | 80 |
8 files changed, 110 insertions, 4 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a7d8a241acc..905f60d2a07 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2771,6 +2771,8 @@ public: const AttributeList *AttrList); void checkUnusedDeclAttributes(Declarator &D); + + void CheckBoolLikeConversion(Expr *E, SourceLocation CC); /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ea4f3476b6c..31b643f1385 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6559,6 +6559,13 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { continue; AnalyzeImplicitConversions(S, ChildExpr, CC); } + if (BO && BO->isLogicalOp()) { + S.CheckBoolLikeConversion(BO->getLHS(), BO->getLHS()->getExprLoc()); + S.CheckBoolLikeConversion(BO->getRHS(), BO->getRHS()->getExprLoc()); + } + if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) + if (U->getOpcode() == UO_LNot) + S.CheckBoolLikeConversion(U->getSubExpr(), CC); } } // end anonymous namespace @@ -6617,6 +6624,18 @@ static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { return false; } +/// CheckBoolLikeConversion - Check conversion of given expression to boolean. +/// Input argument E is a logical expression. +static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { + if (S.getLangOpts().Bool) + return; + CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); +} + +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 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index de080117b49..dde3f3764f1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12984,6 +12984,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { << T << E->getSourceRange(); return ExprError(); } + CheckBoolLikeConversion(E, Loc); } return E; diff --git a/clang/test/Analysis/NSContainers.m b/clang/test/Analysis/NSContainers.m index 4b349264568..402ce2c90a1 100644 --- a/clang/test/Analysis/NSContainers.m +++ b/clang/test/Analysis/NSContainers.m @@ -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); diff --git a/clang/test/Analysis/logical-ops.c b/clang/test/Analysis/logical-ops.c index afaa2f10778..0b63bc9ec83 100644 --- a/clang/test/Analysis/logical-ops.c +++ b/clang/test/Analysis/logical-ops.c @@ -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); diff --git a/clang/test/Analysis/objc-boxing.m b/clang/test/Analysis/objc-boxing.m index c23192e17e5..73386f463bc 100644 --- a/clang/test/Analysis/objc-boxing.m +++ b/clang/test/Analysis/objc-boxing.m @@ -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); diff --git a/clang/test/Sema/exprs.c b/clang/test/Sema/exprs.c index 2fb17e4880c..17b1aa2851b 100644 --- a/clang/test/Sema/exprs.c +++ b/clang/test/Sema/exprs.c @@ -244,6 +244,10 @@ void test22() { 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; } diff --git a/clang/test/Sema/warn-tautological-compare.c b/clang/test/Sema/warn-tautological-compare.c new file mode 100644 index 00000000000..2856eddc7b0 --- /dev/null +++ b/clang/test/Sema/warn-tautological-compare.c @@ -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'}} + } + + |