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 e8cd6b081de16..1453424385033 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. | 
