aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-02-01 05:53:12 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-02-01 05:53:12 +0000
commit7b48a2986345480241f3b8209f71bb21b0530b4f (patch)
tree6b8de705a3c6c110fcb3dbc6c12a62d6799d6ad5 /lib/AST/ExprConstant.cpp
parentb223d8c4266655fe7a9491a0aff0263597672823 (diff)
constexpr: overflow checking for integral and floating-point arithmetic.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149473 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp45
1 files changed, 38 insertions, 7 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 0f8de63bba..731bddd6b8 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -45,6 +45,7 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include <cstring>
+#include <functional>
using namespace clang;
using llvm::APSInt;
@@ -4138,6 +4139,23 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
A.getLValueFrame() == B.getLValueFrame();
}
+/// Perform the given integer operation, which is known to need at most BitWidth
+/// bits, and check for overflow in the original type (if that type was not an
+/// unsigned type).
+template<typename Operation>
+static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op) {
+ if (LHS.isUnsigned())
+ return Op(LHS, RHS);
+
+ 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());
+ return Result;
+}
+
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->isAssignmentOp())
return Error(E);
@@ -4476,9 +4494,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
default:
return Error(E);
- case BO_Mul: return Success(LHS * RHS, E);
- case BO_Add: return Success(LHS + RHS, E);
- case BO_Sub: return Success(LHS - RHS, E);
+ case BO_Mul:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>()), E);
+ case BO_Add:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() + 1,
+ std::plus<APSInt>()), E);
+ case BO_Sub:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() + 1,
+ std::minus<APSInt>()), E);
case BO_And: return Success(LHS & RHS, E);
case BO_Xor: return Success(LHS ^ RHS, E);
case BO_Or: return Success(LHS | RHS, E);
@@ -5078,17 +5105,21 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
default: return Error(E);
case BO_Mul:
Result.multiply(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Add:
Result.add(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Sub:
Result.subtract(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Div:
Result.divide(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
}
+
+ if (Result.isInfinity() || Result.isNaN())
+ CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN();
+ return true;
}
bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {