make our existing "switch on bool" warning work for C. Since

the result of comparisons are 'int' in C, it doesn't work to
test just the result type of the expression.

llvm-svn: 101576
This commit is contained in:
Chris Lattner 2010-04-16 23:34:13 +00:00
parent 12563b3495
commit 4ebae65d6a
5 changed files with 79 additions and 4 deletions

View File

@ -199,6 +199,12 @@ public:
/// \brief Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
/// C.
bool isKnownToHaveBooleanValue() const;
/// isIntegerConstantExpr - Return true if this expression is a valid integer
/// constant expression, and, if so, return its value in Result. If not a
/// valid i-c-e, return false and fill in Loc (if specified) with the location
@ -304,7 +310,7 @@ public:
/// its subexpression. If that subexpression is also a ParenExpr,
/// then this method recursively returns its subexpression, and so forth.
/// Otherwise, the method returns the current Expr.
Expr* IgnoreParens();
Expr *IgnoreParens();
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
/// or CastExprs, returning their operand.
@ -333,7 +339,7 @@ public:
/// temporary object.
const Expr *getTemporaryObject() const;
const Expr* IgnoreParens() const {
const Expr *IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
}
const Expr *IgnoreParenCasts() const {

View File

@ -2782,7 +2782,7 @@ def err_default_not_in_switch : Error<
"'default' statement not in switch statement">;
def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
def warn_bool_switch_condition : Warning<
"switch condition is a bool">;
"switch condition has boolean value">;
def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">,
InGroup<DiagGroup<"switch">>;

View File

@ -27,6 +27,65 @@
#include <algorithm>
using namespace clang;
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
/// C.
bool Expr::isKnownToHaveBooleanValue() const {
// If this value has _Bool type, it is obvious 0/1.
if (getType()->isBooleanType()) return true;
// If this is a non-scalar-integer type, we don't care enough to try.
if (!getType()->isIntegralType()) return false;
if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
return PE->getSubExpr()->isKnownToHaveBooleanValue();
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
switch (UO->getOpcode()) {
case UnaryOperator::Plus:
case UnaryOperator::Extension:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
default:
return false;
}
}
if (const CastExpr *CE = dyn_cast<CastExpr>(this))
return CE->getSubExpr()->isKnownToHaveBooleanValue();
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
switch (BO->getOpcode()) {
default: return false;
case BinaryOperator::LT: // Relational operators.
case BinaryOperator::GT:
case BinaryOperator::LE:
case BinaryOperator::GE:
case BinaryOperator::EQ: // Equality operators.
case BinaryOperator::NE:
case BinaryOperator::LAnd: // AND operator.
case BinaryOperator::LOr: // Logical OR operator.
return true;
case BinaryOperator::And: // Bitwise AND operator.
case BinaryOperator::Xor: // Bitwise XOR operator.
case BinaryOperator::Or: // Bitwise OR operator.
// Handle things like (x==2)|(y==12).
return BO->getLHS()->isKnownToHaveBooleanValue() &&
BO->getRHS()->isKnownToHaveBooleanValue();
case BinaryOperator::Comma:
case BinaryOperator::Assign:
return BO->getRHS()->isKnownToHaveBooleanValue();
}
}
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
return false;
}
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//

View File

@ -593,7 +593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
return StmtError();
}
if (CondTypeBeforePromotion->isBooleanType()) {
if (CondExpr->isKnownToHaveBooleanValue()) {
// switch(bool_expr) {...} is often a programmer error, e.g.
// switch(n && mask) { ... } // Doh - should be "n & mask".
// One can always use an if statement instead of switch(bool_expr).

View File

@ -41,3 +41,13 @@ void test11(int bit) {
{
}
}
// rdar://3271964
enum Numbers { kOne, kTwo, kThree, kFour};
int test12(enum Numbers num) {
switch (num == kOne) {// expected-warning {{switch condition has boolean value}}
default:
case kThree:
break;
}
}