summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-01-06 22:07:33 +0000
committerJohn McCall <rjmccall@apple.com>2010-01-06 22:07:33 +0000
commit2ce81adbb3457d70ce2713ba9e59dd2bf08fb48c (patch)
tree5524b42d24712c16e4121a023bcbfaad623ccc4d /clang/lib
parentdfdda291e0da47ee002564c9d78c3fc8e0c15dc0 (diff)
downloadbcm5719-llvm-2ce81adbb3457d70ce2713ba9e59dd2bf08fb48c.tar.gz
bcm5719-llvm-2ce81adbb3457d70ce2713ba9e59dd2bf08fb48c.zip
Derive tighter ranges for & and >> in the conversion-checking code.
llvm-svn: 92862
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp44
1 files changed, 38 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 00e7242808a..463a03801a4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1607,7 +1607,13 @@ struct IntRange {
// Returns the supremum of two ranges: i.e. their conservative merge.
static IntRange join(const IntRange &L, const IntRange &R) {
return IntRange(std::max(L.Width, R.Width),
- L.NonNegative && R.NonNegative);
+ L.NonNegative && R.NonNegative);
+ }
+
+ // Returns the infinum of two ranges: i.e. their aggressive merge.
+ static IntRange meet(const IntRange &L, const IntRange &R) {
+ return IntRange(std::min(L.Width, R.Width),
+ L.NonNegative || R.NonNegative);
}
};
@@ -1668,8 +1674,12 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
IntRange OutputTypeRange = IntRange::forType(C, CE->getType());
+ bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast);
+ if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown)
+ isIntegerCast = CE->getSubExpr()->getType()->isIntegerType();
+
// Assume that non-integer casts can span the full range of the type.
- if (CE->getCastKind() != CastExpr::CK_IntegralCast)
+ if (!isIntegerCast)
return OutputTypeRange;
IntRange SubRange
@@ -1719,17 +1729,39 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
case BinaryOperator::PtrMemI:
return IntRange::forType(C, E->getType());
+ // Bitwise-and uses the *infinum* of the two source ranges.
+ case BinaryOperator::And:
+ return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
+ GetExprRange(C, BO->getRHS(), MaxWidth));
+
// Left shift gets black-listed based on a judgement call.
case BinaryOperator::Shl:
return IntRange::forType(C, E->getType());
- // Various special cases.
- case BinaryOperator::Shr:
- // TODO: if the RHS is constant, change the width as appropriate.
- return GetExprRange(C, BO->getLHS(), MaxWidth);
+ // Right shift by a constant can narrow its left argument.
+ case BinaryOperator::Shr: {
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+
+ // If the shift amount is a positive constant, drop the width by
+ // that much.
+ llvm::APSInt shift;
+ if (BO->getRHS()->isIntegerConstantExpr(shift, C) &&
+ shift.isNonNegative()) {
+ unsigned zext = shift.getZExtValue();
+ if (zext >= L.Width)
+ L.Width = (L.NonNegative ? 0 : 1);
+ else
+ L.Width -= zext;
+ }
+
+ return L;
+ }
+
+ // Comma acts as its right operand.
case BinaryOperator::Comma:
return GetExprRange(C, BO->getRHS(), MaxWidth);
+ // Black-list pointer subtractions.
case BinaryOperator::Sub:
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forType(C, E->getType());
OpenPOWER on IntegriCloud