diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index e8cd6b0..1453424 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -368,6 +368,21 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs, return false; } +/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of +/// potentially integral-promoted expression @p expr. +static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { + const ImplicitCastExpr *ImplicitCast = + dyn_cast_or_null<ImplicitCastExpr>(expr); + if (ImplicitCast != NULL) { + const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr(); + QualType TypeBeforePromotion = ExprBeforePromotion->getType(); + if (TypeBeforePromotion->isIntegralType()) { + return TypeBeforePromotion; + } + } + return expr->getType(); +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -382,11 +397,30 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, Expr *CondExpr = SS->getCond(); QualType CondType = CondExpr->getType(); - if (!CondExpr->isTypeDependent() && - !CondType->isIntegerType()) { // C99 6.8.4.2p1 - Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) - << CondType << CondExpr->getSourceRange(); - return StmtError(); + // C++ 6.4.2.p2: + // Integral promotions are performed (on the switch condition). + // + // A case value unrepresentable by the original switch condition + // type (before the promotion) doesn't make sense, even when it can + // be represented by the promoted type. Therefore we need to find + // the pre-promotion type of the switch condition. + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExpr); + + if (!CondExpr->isTypeDependent()) { + if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 + Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) + << CondType << CondExpr->getSourceRange(); + return StmtError(); + } + + if (CondTypeBeforePromotion->isBooleanType()) { + // 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). + Diag(SwitchLoc, diag::warn_bool_switch_condition) + << CondExpr->getSourceRange(); + } } // Get the bitwidth of the switched-on value before promotions. We must @@ -395,8 +429,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue? 0 - : static_cast<unsigned>(Context.getTypeSize(CondType)); - bool CondIsSigned = CondType->isSignedIntegerType(); + : static_cast<unsigned>(Context.getTypeSize(CondTypeBeforePromotion)); + bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType(); // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after @@ -448,7 +482,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Lo, CondType); + ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -504,7 +538,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Hi, CondType); + ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. |