[cfe-commits] r173377 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticASTKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ExprConstant.cpp lib/Sema/SemaChecking.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaStmt.cpp test/Sema/switch-1.c

Fariborz Jahanian fjahanian at apple.com
Thu Jan 24 14:11:45 PST 2013


Author: fjahanian
Date: Thu Jan 24 16:11:45 2013
New Revision: 173377

URL: http://llvm.org/viewvc/llvm-project?rev=173377&view=rev
Log:
Patch to check for integer overflow. It has been
commented on and approved by Richard Smith.

Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/Sema/switch-1.c

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Jan 24 16:11:45 2013
@@ -570,6 +570,9 @@
   /// integer.
   llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
                           SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
+  
+  void EvaluateForOverflow(const ASTContext &Ctx,
+                           SmallVectorImpl<PartialDiagnosticAt> *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.

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu Jan 24 16:11:45 2013
@@ -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<
+  "overflow in case constant expression results in value %0 of type %1">,
+  InGroup<DiagGroup<"integer-overflow">>;
 
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 24 16:11:45 2013
@@ -5756,9 +5756,6 @@
 def warn_case_value_overflow : Warning<
   "overflow converting case value to switch condition type (%0 to %1)">,
   InGroup<Switch>;
-def warn_case_constant_overflow : Warning<
-  "overflow in case constant expression results in value %0">,
-  InGroup<Switch>;
 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'">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 24 16:11:45 2013
@@ -3993,7 +3993,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.
@@ -7328,11 +7329,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);

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jan 24 16:11:45 2013
@@ -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<ASTContext&>(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<typename LocArg>
@@ -506,8 +512,12 @@
     /// Should we continue evaluation as much as possible after encountering a
     /// construct which can't be folded?
     bool keepEvaluatingAfterFailure() {
-      return CheckingPotentialConstantExpression &&
-             EvalStatus.Diag && EvalStatus.Diag->empty();
+      // Should return true in IntOverflowCheckMode, so that we check for
+      // overflow even if some subexpressions can't be evaluated as constants.
+      // subexpressions can't be evaluated as constants.
+      return IntOverflowCheckMode ||
+             (CheckingPotentialConstantExpression &&
+              EvalStatus.Diag && EvalStatus.Diag->empty());
     }
   };
 
@@ -4418,8 +4428,14 @@
 
   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.Ctx.getDiagnostics().Report(E->getExprLoc(),
+        diag::warn_integer_constant_overflow)
+          << Result.toString(10) << E->getType();
+    else
+      HandleOverflow(Info, E, Value, E->getType());
+  }
   return Result;
 }
 
@@ -6260,26 +6276,39 @@
   return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
 }
 
-/// EvaluateAsRValue - Return true if this is a constant which we can fold using
-/// any crazy technique (that has nothing to do with language standards) that
-/// 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 {
+static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
+                                 const ASTContext &Ctx, bool &IsConst) {
   // Fast-path evaluations of integer literals, since we sometimes see files
   // containing vast quantities of these.
-  if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(this)) {
+  if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) {
     Result.Val = APValue(APSInt(L->getValue(),
                                 L->getType()->isUnsignedIntegerType()));
+    IsConst = true;
     return true;
   }
-
+  
   // FIXME: Evaluating values of large array and record types can cause
   // performance problems. Only do so in C++11 for now.
-  if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
-      !Ctx.getLangOpts().CPlusPlus11)
-    return false;
+  if (Exp->isRValue() && (Exp->getType()->isArrayType() ||
+                          Exp->getType()->isRecordType()) &&
+      !Ctx.getLangOpts().CPlusPlus11) {
+    IsConst = false;
+    return true;
+  }
+  return false;
+}
+
 
+/// EvaluateAsRValue - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// 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 IsConst;
+  if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
+    return IsConst;
+  
   EvalInfo Info(Ctx, Result);
   return ::EvaluateAsRValue(Info, this, Result.Val);
 }
@@ -6376,6 +6405,17 @@
   return EvalResult.Val.getInt();
 }
 
+void Expr::EvaluateForOverflow(const ASTContext &Ctx,
+                    SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+  bool IsConst;
+  EvalResult EvalResult;
+  EvalResult.Diag = Diags;
+  if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
+    EvalInfo Info(Ctx, EvalResult, true);
+    (void)::EvaluateAsRValue(Info, this, EvalResult.Val);
+  }
+}
+
  bool Expr::EvalResult::isGlobalLValue() const {
    assert(Val.isLValue());
    return IsGlobalLValue(Val.getLValueBase());

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jan 24 16:11:45 2013
@@ -5183,6 +5183,18 @@
   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<BinaryOperator>(E->IgnoreParens())) {
+    unsigned Opc = BExpr->getOpcode();
+    if (Opc != BO_Add && Opc != BO_Sub && Opc != BO_Mul)
+      return;
+    llvm::SmallVector<PartialDiagnosticAt, 4> Diags;
+    E->EvaluateForOverflow(Context, &Diags);
+  }
+}
+
 namespace {
 /// \brief Visitor for expressions which looks for unsequenced operations on the
 /// same object.
@@ -5622,9 +5634,12 @@
   }
 }
 
-void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc) {
+void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
+                              bool IsConstexpr) {
   CheckImplicitConversions(E, CheckLoc);
   CheckUnsequencedOperations(E);
+  if (!IsConstexpr && !E->isValueDependent())
+    CheckForIntOverflow(E);
 }
 
 void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 24 16:11:45 2013
@@ -7045,7 +7045,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;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 24 16:11:45 2013
@@ -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);
 }
 

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Jan 24 16:11:45 2013
@@ -338,6 +338,12 @@
       // Recover from an error by just forgetting about it.
     }
   }
+  
+  LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
+                               getLangOpts().CPlusPlus11).take();
+  if (RHSVal)
+    RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
+                                 getLangOpts().CPlusPlus11).take();
 
   CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
                                         ColonLoc);
@@ -732,14 +738,7 @@
       } else {
         // We already verified that the expression has a i-c-e value (C99
         // 6.8.4.2p3) - get that value now.
-        SmallVector<PartialDiagnosticAt, 8> 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.

Modified: cfe/trunk/test/Sema/switch-1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/switch-1.c?rev=173377&r1=173376&r2=173377&view=diff
==============================================================================
--- cfe/trunk/test/Sema/switch-1.c (original)
+++ cfe/trunk/test/Sema/switch-1.c Thu Jan 24 16:11:45 2013
@@ -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 {{overflow in case constant expression results in value -2147483647 of type 'int'}}
       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 {{overflow in case constant expression results in value -4 of type 'long'}}
       return 2;
+    case (123456 *789012) + 1:  // expected-warning {{overflow in case constant expression results in value -1375982336 of type 'int'}}
+      return 3;
     case 2147483647:
       return 0;
   }





More information about the cfe-commits mailing list