Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h (revision 172829) +++ include/clang/AST/Expr.h (working copy) @@ -537,7 +537,8 @@ /// this function returns true, it returns the folded constant in Result. If /// the expression is a glvalue, an lvalue-to-rvalue conversion will be /// applied. - bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const; + bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, + bool OverflowCheckMode=false) const; /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we we can fold and convert to a boolean condition using @@ -570,6 +571,9 @@ /// integer. llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl *Diag=0) const; + + void EvaluateKnownConstIntForOverflow(const ASTContext &Ctx, + SmallVectorImpl *Diag) const; /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an /// lvalue with link time known address, with no side-effects. Index: include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- include/clang/Basic/DiagnosticASTKinds.td (revision 172829) +++ include/clang/Basic/DiagnosticASTKinds.td (working copy) @@ -106,6 +106,9 @@ "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " "see all)">; def note_constexpr_call_here : Note<"in call to '%0'">; +def warn_integer_constant_overflow : Warning< + "integer constant overflow in expression">, + InGroup>; // inline asm related. let CategoryName = "Inline Assembly Issue" in { Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td (revision 172829) +++ include/clang/Basic/DiagnosticSemaKinds.td (working copy) @@ -5735,9 +5735,6 @@ def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">, InGroup; -def warn_case_constant_overflow : Warning< - "overflow in case constant expression results in value %0">, - InGroup; def err_duplicate_case : Error<"duplicate case value '%0'">; def err_duplicate_case_differing_expr : Error< "duplicate case value: '%0' and '%1' both equal '%2'">; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h (revision 172829) +++ include/clang/Sema/Sema.h (working copy) @@ -3984,7 +3984,8 @@ : SourceLocation()); } ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, - bool DiscardedValue = false); + bool DiscardedValue = false, + bool IsConstexpr = false); StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. @@ -7322,11 +7323,13 @@ SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); + void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(Expr *E); /// \brief Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. - void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation()); + void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), + bool IsConstexpr = false); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp (revision 172829) +++ lib/AST/ExprConstant.cpp (working copy) @@ -384,13 +384,17 @@ /// expression is a potential constant expression? If so, some diagnostics /// are suppressed. bool CheckingPotentialConstantExpression; + + bool IntOverflowCheckMode; - EvalInfo(const ASTContext &C, Expr::EvalStatus &S) + EvalInfo(const ASTContext &C, Expr::EvalStatus &S, + bool OverflowCheckMode=false) : Ctx(const_cast(C)), EvalStatus(S), CurrentCall(0), CallStackDepth(0), NextCallIndex(1), BottomFrame(*this, SourceLocation(), 0, 0, 0), EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false), - CheckingPotentialConstantExpression(false) {} + CheckingPotentialConstantExpression(false), + IntOverflowCheckMode(OverflowCheckMode) {} void setEvaluatingDecl(const VarDecl *VD, APValue &Value) { EvaluatingDecl = VD; @@ -474,6 +478,8 @@ return OptionalDiagnostic(); } + bool getIntOverflowCheckMode() { return IntOverflowCheckMode; } + /// Diagnose that the evaluation does not produce a C++11 core constant /// expression. template @@ -4419,8 +4425,13 @@ APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); APSInt Result = Value.trunc(LHS.getBitWidth()); - if (Result.extend(BitWidth) != Value) - HandleOverflow(Info, E, Value, E->getType()); + if (Result.extend(BitWidth) != Value) { + if (Info.getIntOverflowCheckMode()) + Info.Diag(E->getExprLoc(), + diag::warn_integer_constant_overflow); + else + HandleOverflow(Info, E, Value, E->getType()); + } return Result; } @@ -6264,7 +6275,8 @@ /// we want to. If this function returns true, it returns the folded constant /// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion /// will be applied to the result. -bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { +bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, + bool OverflowCheckMode) const { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. if (const IntegerLiteral *L = dyn_cast(this)) { @@ -6279,7 +6291,7 @@ !Ctx.getLangOpts().CPlusPlus11) return false; - EvalInfo Info(Ctx, Result); + EvalInfo Info(Ctx, Result, OverflowCheckMode); return ::EvaluateAsRValue(Info, this, Result.Val); } @@ -6375,6 +6387,13 @@ return EvalResult.Val.getInt(); } +void Expr::EvaluateKnownConstIntForOverflow(const ASTContext &Ctx, + SmallVectorImpl *Diags) const { + EvalResult EvalResult; + EvalResult.Diag = Diags; + (void)EvaluateAsRValue(EvalResult, Ctx, true /*OverflowCheckMode*/); +} + bool Expr::EvalResult::isGlobalLValue() const { assert(Val.isLValue()); return IsGlobalLValue(Val.getLValueBase()); Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp (revision 172829) +++ lib/Sema/SemaChecking.cpp (working copy) @@ -14,6 +14,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -5171,6 +5172,22 @@ AnalyzeImplicitConversions(*this, E, CC); } +/// Diagnose when expression is an integer constant expression and its evaluation +/// results in integer overflow +void Sema::CheckForIntOverflow (Expr *E) { + if (const BinaryOperator *BExpr = dyn_cast(E->IgnoreParens())) { + unsigned Opc = BExpr->getOpcode(); + if (Opc != BO_Add && Opc != BO_Sub && Opc != BO_Mul) + return; + llvm::SmallVector Diags; + E->EvaluateKnownConstIntForOverflow(Context, &Diags); + if (Diags.size() && + Diags[0].second.getDiagID() == diag::warn_integer_constant_overflow) + Diag(Diags[0].first, Diags[0].second.getDiagID()); + + } +} + namespace { /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. @@ -5610,9 +5627,12 @@ } } -void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc) { +void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, + bool IsConstexpr) { CheckImplicitConversions(E, CheckLoc); CheckUnsequencedOperations(E); + if (!IsConstexpr) + CheckForIntOverflow(E); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 172829) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -6985,7 +6985,9 @@ // struct T { S a, b; } t = { Temp(), Temp() } // // we should destroy the first Temp before constructing the second. - ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation()); + ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation(), + false, + VDecl->isConstexpr()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp (revision 172829) +++ lib/Sema/SemaExprCXX.cpp (working copy) @@ -5469,7 +5469,8 @@ } ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, - bool DiscardedValue) { + bool DiscardedValue, + bool IsConstexpr) { ExprResult FullExpr = Owned(FE); if (!FullExpr.get()) @@ -5497,7 +5498,7 @@ return ExprError(); } - CheckCompletedExpr(FullExpr.get(), CC); + CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); return MaybeCreateExprWithCleanups(FullExpr); } Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp (revision 172829) +++ lib/Sema/SemaStmt.cpp (working copy) @@ -338,6 +338,10 @@ // Recover from an error by just forgetting about it. } } + + LHSVal = ActOnFinishFullExpr(LHSVal).take(); + if (RHSVal) + RHSVal = ActOnFinishFullExpr(RHSVal).take(); CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, ColonLoc); @@ -732,14 +736,7 @@ } else { // We already verified that the expression has a i-c-e value (C99 // 6.8.4.2p3) - get that value now. - SmallVector Diags; - LoVal = Lo->EvaluateKnownConstInt(Context, &Diags); - if (Diags.size() == 1 && - Diags[0].second.getDiagID() == diag::note_constexpr_overflow) { - Diag(Lo->getLocStart(), diag::warn_case_constant_overflow) << - LoVal.toString(10); - Diag(Diags[0].first, Diags[0].second); - } + LoVal = Lo->EvaluateKnownConstInt(Context); // If the LHS is not the same type as the condition, insert an implicit // cast. Index: test/Sema/switch-1.c =================================================================== --- test/Sema/switch-1.c (revision 172829) +++ test/Sema/switch-1.c (working copy) @@ -4,12 +4,12 @@ int f(int i) { switch (i) { - case 2147483647 + 2: // expected-note {{value 2147483649 is outside the range of representable values of type 'int'}} \ - // expected-warning {{overflow in case constant expression results in value -2147483647}} + case 2147483647 + 2: // expected-warning {{integer constant overflow in expression}} return 1; - case 9223372036854775807L * 4 : // expected-note {{value 36893488147419103228 is outside the range of representable values of type 'long'}} \ - // expected-warning {{overflow in case constant expression results in value -4}} + case 9223372036854775807L * 4: // expected-warning {{integer constant overflow in expression}} return 2; + case (123456 *789012) + 1: // expected-warning {{integer constant overflow in expression}} + return 3; case 2147483647: return 0; }