unsigned SClass : 3;
bool ThreadSpecified : 1;
bool HasCXXDirectInit : 1;
-
+
+ /// DeclaredInCondition - Whether this variable was declared in a
+ /// condition, e.g., if (int x = foo()) { ... }.
+ bool DeclaredInCondition : 1;
+
// Move to DeclGroup when it is implemented.
SourceLocation TypeSpecStartLoc;
friend class StmtIteratorBase;
SourceLocation TSSL = SourceLocation())
: ValueDecl(DK, DC, L, Id, T, PrevDecl), Init(0),
ThreadSpecified(false), HasCXXDirectInit(false),
- TypeSpecStartLoc(TSSL) { SClass = SC; }
+ DeclaredInCondition(false), TypeSpecStartLoc(TSSL) {
+ SClass = SC;
+ }
public:
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
return HasCXXDirectInit;
}
+ /// isDeclaredInCondition - Whether this variable was declared as
+ /// part of a condition in an if/switch/while statement, e.g.,
+ /// @code
+ /// if (int x = foo()) { ... }
+ /// @endcode
+ bool isDeclaredInCondition() const {
+ return DeclaredInCondition;
+ }
+ void setDeclaredInCondition(bool InCondition) {
+ DeclaredInCondition = InCondition;
+ }
+
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
bool hasLocalStorage() const {
DIAG(err_not_tag_in_scope, ERROR,
"%0 does not name a tag member in the specified scope")
+DIAG(warn_value_always_zero, WARNING,
+ "%0 is always zero in this context")
+DIAG(warn_value_always_false, WARNING,
+ "%0 is always false in this context")
// assignment related diagnostics (also for argument passing, returning, etc).
// FIXME: %2 is an english string here.
/// interrelates with other control flow statements.
unsigned Flags : 8;
+ /// WithinElse - Whether this scope is part of the "else" branch in
+ /// its parent ControlScope.
+ bool WithinElse : 1;
+
/// FnParent - If this scope has a parent scope that is a function body, this
/// pointer is non-null and points to it. This is used for label processing.
Scope *FnParent;
/// there is no containing break/continue scope.
Scope *BreakParent, *ContinueParent;
+ /// ControlParent - This is a direct link to the immediately
+ /// preceeding ControlParent if this scope is not one, or null if
+ /// there is no containing control scope.
+ Scope *ControlParent;
+
/// BlockParent - This is a direct link to the immediately containing
/// BlockScope if this scope is not one, or null if there is none.
Scope *BlockParent;
return const_cast<Scope*>(this)->getBreakParent();
}
+ Scope *getControlParent() { return ControlParent; }
+ const Scope *getControlParent() const { return ControlParent; }
+
Scope *getBlockParent() { return BlockParent; }
const Scope *getBlockParent() const { return BlockParent; }
return getFlags() & Scope::TemplateParamScope;
}
+ /// isWithinElse - Whether we are within the "else" of the
+ /// ControlParent (if any).
+ bool isWithinElse() const { return WithinElse; }
+
+ void setWithinElse(bool WE) { WithinElse = WE; }
+
/// Init - This is used by the parser to implement scope caching.
///
void Init(Scope *Parent, unsigned ScopeFlags) {
FnParent = AnyParent->FnParent;
BreakParent = AnyParent->BreakParent;
ContinueParent = AnyParent->ContinueParent;
+ 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.
if (Flags & FnScope) FnParent = this;
if (Flags & BreakScope) BreakParent = this;
if (Flags & ContinueScope) ContinueParent = this;
+ if (Flags & ControlScope) ControlParent = this;
if (Flags & BlockScope) BlockParent = this;
if (Flags & TemplateParamScope) TemplateParamParent = this;
DeclsInScope.clear();
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
+ bool WithinElse = CurScope->isWithinElse();
+ CurScope->setWithinElse(true);
ElseStmtLoc = Tok.getLocation();
ElseStmt = ParseStatement();
+ CurScope->setWithinElse(WithinElse);
// Pop the 'else' scope if needed.
InnerScope.Exit();
// check if referencing an identifier with __attribute__((deprecated)).
if (VD->getAttr<DeprecatedAttr>())
Diag(Loc, diag::warn_deprecated) << VD->getDeclName();
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD)) {
+ if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
+ Scope *CheckS = S;
+ while (CheckS) {
+ if (CheckS->isWithinElse() &&
+ CheckS->getControlParent()->isDeclScope(Var)) {
+ if (Var->getType()->isBooleanType())
+ Diag(Loc, diag::warn_value_always_false) << Var->getDeclName();
+ else
+ Diag(Loc, diag::warn_value_always_zero) << Var->getDeclName();
+ break;
+ }
+
+ // Move up one more control parent to check again.
+ CheckS = CheckS->getControlParent();
+ if (CheckS)
+ CheckS = CheckS->getParent();
+ }
+ }
+ }
// Only create DeclRefExpr's for valid Decl's.
if (VD->isInvalidDecl())
return true;
AddInitializerToDecl(Dcl, AssignExprVal);
+ // Mark this variable as one that is declared within a conditional.
+ if (VarDecl *VD = dyn_cast<VarDecl>((Decl *)Dcl))
+ VD->setDeclaredInCondition(true);
+
return new CXXConditionDeclExpr(StartLoc, EqualLoc,
cast<VarDecl>(static_cast<Decl *>(Dcl)));
}
--- /dev/null
+// RUN: clang -fsyntax-only -verify %s
+// rdar://6425550
+int bar();
+void do_something(int);
+
+int foo() {
+ if (int X = bar()) {
+ return X;
+ } else {
+ do_something(X); // expected-warning{{'X' is always zero in this context}}
+ }
+}
+
+bool foo2() {
+ if (bool B = bar()) {
+ if (int Y = bar()) {
+ return B;
+ } else {
+ do_something(Y); // expected-warning{{'Y' is always zero in this context}}
+ return B;
+ }
+ } else {
+ if (bool B2 = B) { // expected-warning{{'B' is always false in this context}}
+ 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}}
+ }
+ return B; // expected-warning{{'B' is always false in this context}}
+ }
+}