From 13a2c03801423254f434127ee8a624e5be1ab4d4 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 5 Nov 2009 17:49:26 +0000 Subject: [PATCH] Eliminate some false positives due to a thinko in the "'blah' is always zero in this context" warning logic. Also, make the diagnostic itself more precise when referring to pointer values ("NULL" vs. "zero"). llvm-svn: 86143 --- .../include/clang/Basic/DiagnosticSemaKinds.td | 4 ++-- clang/include/clang/Parse/Scope.h | 6 ++---- clang/lib/Sema/SemaExpr.cpp | 18 +++++++----------- clang/test/SemaCXX/warn-for-var-in-else.cpp | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2309908df7b4..06b09a0b7304 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1787,8 +1787,8 @@ def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup; -def warn_value_always_zero : Warning<"%0 is always zero in this context">; -def warn_value_always_false : Warning<"%0 is always false in this context">; +def warn_value_always_zero : Warning< + "%0 is always %select{zero|false|NULL}1 in this context">; // assignment related diagnostics (also for argument passing, returning, etc). // FIXME: %2 is an english string here. diff --git a/clang/include/clang/Parse/Scope.h b/clang/include/clang/Parse/Scope.h index 480b94f73f62..c6a1e53472c1 100644 --- a/clang/include/clang/Parse/Scope.h +++ b/clang/include/clang/Parse/Scope.h @@ -275,7 +275,8 @@ public: AnyParent = Parent; Depth = AnyParent ? AnyParent->Depth+1 : 0; Flags = ScopeFlags; - + WithinElse = false; + if (AnyParent) { FnParent = AnyParent->FnParent; BreakParent = AnyParent->BreakParent; @@ -283,13 +284,10 @@ public: ControlParent = AnyParent->ControlParent; BlockParent = AnyParent->BlockParent; TemplateParamParent = AnyParent->TemplateParamParent; - WithinElse = AnyParent->WithinElse; - } else { FnParent = BreakParent = ContinueParent = BlockParent = 0; ControlParent = 0; TemplateParamParent = 0; - WithinElse = false; } // If this scope is a function or contains breaks/continues, remember it. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f1d6f2bb17ce..f94017129b02 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -814,22 +814,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // information to check this property. if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; - while (CheckS) { + while (CheckS && CheckS->getControlParent()) { if (CheckS->isWithinElse() && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { - if (Var->getType()->isBooleanType()) - ExprError(Diag(Loc, diag::warn_value_always_false) - << Var->getDeclName()); - else - ExprError(Diag(Loc, diag::warn_value_always_zero) - << Var->getDeclName()); + ExprError(Diag(Loc, diag::warn_value_always_zero) + << Var->getDeclName() + << (Var->getType()->isPointerType()? 2 : + Var->getType()->isBooleanType()? 1 : 0)); break; } - // Move up one more control parent to check again. - CheckS = CheckS->getControlParent(); - if (CheckS) - CheckS = CheckS->getParent(); + // Move to the parent of this scope. + CheckS = CheckS->getParent(); } } } else if (FunctionDecl *Func = dyn_cast(D)) { diff --git a/clang/test/SemaCXX/warn-for-var-in-else.cpp b/clang/test/SemaCXX/warn-for-var-in-else.cpp index f73c60689446..c46b30640fb2 100644 --- a/clang/test/SemaCXX/warn-for-var-in-else.cpp +++ b/clang/test/SemaCXX/warn-for-var-in-else.cpp @@ -2,6 +2,7 @@ // rdar://6425550 int bar(); void do_something(int); +int *get_ptr(); int foo() { if (int X = bar()) { @@ -25,7 +26,20 @@ bool foo2() { do_something(B); // expected-warning{{'B' is always false in this context}} } else if (B2) { // expected-warning{{'B2' is always false in this context}} do_something(B); // expected-warning{{'B' is always false in this context}} + do_something(B2); // expected-warning{{'B2' is always false in this context}} } return B; // expected-warning{{'B' is always false in this context}} } } + +void foo3() { + if (int *P1 = get_ptr()) + do_something(*P1); + else if (int *P2 = get_ptr()) { + do_something(*P1); // expected-warning{{'P1' is always NULL in this context}} + do_something(*P2); + } else { + do_something(*P1); // expected-warning{{'P1' is always NULL in this context}} + do_something(*P2); // expected-warning{{'P2' is always NULL in this context}} + } +}