Derive tighter ranges for & and >> in the conversion-checking code.

llvm-svn: 92862
This commit is contained in:
John McCall 2010-01-06 22:07:33 +00:00
parent dfdda291e0
commit 2ce81adbb3
2 changed files with 48 additions and 6 deletions

View File

@ -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());

View File

@ -261,3 +261,13 @@ void test18() {
x = (U.a ? 0 : 1);
x = (U.b ? 0 : 1);
}
// None of these should warn.
unsigned char test19(unsigned long u64) {
unsigned char x1 = u64 & 0xff;
unsigned char x2 = u64 >> 56;
unsigned char mask = 0xee;
unsigned char x3 = u64 & mask;
return x1 + x2 + x3;
}