summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-04-16 23:34:13 +0000
committerChris Lattner <sabre@nondot.org>2010-04-16 23:34:13 +0000
commit4ebae65d6af71115de86273e6b27f67e2cde2be7 (patch)
tree84105e5478d10fd5cf0edf6c0fcc62ad210ea0fa
parent12563b34957924ed46ff203bfc9b87a8b6eadf6d (diff)
downloadbcm5719-llvm-4ebae65d6af71115de86273e6b27f67e2cde2be7.tar.gz
bcm5719-llvm-4ebae65d6af71115de86273e6b27f67e2cde2be7.zip
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
-rw-r--r--clang/include/clang/AST/Expr.h10
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/AST/Expr.cpp59
-rw-r--r--clang/lib/Sema/SemaStmt.cpp2
-rw-r--r--clang/test/Sema/statements.c10
5 files changed, 79 insertions, 4 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 68ca2680e91..88e87812d19 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -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 {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 85ca9e9fbb4..69c12398af7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">>;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 72359c245a5..7c715bd3c3a 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -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.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 74c64d38818..cb553932596 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -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).
diff --git a/clang/test/Sema/statements.c b/clang/test/Sema/statements.c
index 52b9c7543d4..e3c41f3e1aa 100644
--- a/clang/test/Sema/statements.c
+++ b/clang/test/Sema/statements.c
@@ -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;
+ }
+} \ No newline at end of file
OpenPOWER on IntegriCloud