From: John McCall Date: Wed, 6 Jan 2010 22:07:33 +0000 (+0000) Subject: Derive tighter ranges for & and >> in the conversion-checking code. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=60fad45739b764886f707bd204eae9ecce6db1f2;p=clang Derive tighter ranges for & and >> in the conversion-checking code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92862 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 00e7242808..463a03801a 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/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()); diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c index 44b1224b52..298bf75642 100644 --- a/test/Sema/conversion.c +++ b/test/Sema/conversion.c @@ -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; +}