222 changes: 160 additions & 62 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10168,15 +10168,23 @@ namespace {
/// Structure recording the 'active' range of an integer-valued
/// expression.
struct IntRange {
/// The number of bits active in the int.
/// The number of bits active in the int. Note that this includes exactly one
/// sign bit if !NonNegative.
unsigned Width;

/// True if the int is known not to have negative values.
/// True if the int is known not to have negative values. If so, all leading
/// bits before Width are known zero, otherwise they are known to be the
/// same as the MSB within Width.
bool NonNegative;

IntRange(unsigned Width, bool NonNegative)
: Width(Width), NonNegative(NonNegative) {}

/// Number of bits excluding the sign bit.
unsigned valueBits() const {
return NonNegative ? Width : Width - 1;
}

/// Returns the range of the bool type.
static IntRange forBoolType() {
return IntRange(1, true);
Expand Down Expand Up @@ -10260,14 +10268,63 @@ struct IntRange {

/// Returns the supremum of two ranges: i.e. their conservative merge.
static IntRange join(IntRange L, IntRange R) {
return IntRange(std::max(L.Width, R.Width),
bool Unsigned = L.NonNegative && R.NonNegative;
return IntRange(std::max(L.valueBits(), R.valueBits()) + !Unsigned,
L.NonNegative && R.NonNegative);
}

/// Returns the infinum of two ranges: i.e. their aggressive merge.
static IntRange meet(IntRange L, IntRange R) {
return IntRange(std::min(L.Width, R.Width),
L.NonNegative || R.NonNegative);
/// Return the range of a bitwise-AND of the two ranges.
static IntRange bit_and(IntRange L, IntRange R) {
unsigned Bits = std::max(L.Width, R.Width);
bool NonNegative = false;
if (L.NonNegative) {
Bits = std::min(Bits, L.Width);
NonNegative = true;
}
if (R.NonNegative) {
Bits = std::min(Bits, R.Width);
NonNegative = true;
}
return IntRange(Bits, NonNegative);
}

/// Return the range of a sum of the two ranges.
static IntRange sum(IntRange L, IntRange R) {
bool Unsigned = L.NonNegative && R.NonNegative;
return IntRange(std::max(L.valueBits(), R.valueBits()) + 1 + !Unsigned,
Unsigned);
}

/// Return the range of a difference of the two ranges.
static IntRange difference(IntRange L, IntRange R) {
// We need a 1-bit-wider range if:
// 1) LHS can be negative: least value can be reduced.
// 2) RHS can be negative: greatest value can be increased.
bool CanWiden = !L.NonNegative || !R.NonNegative;
bool Unsigned = L.NonNegative && R.Width == 0;
return IntRange(std::max(L.valueBits(), R.valueBits()) + CanWiden +
!Unsigned,
Unsigned);
}

/// Return the range of a product of the two ranges.
static IntRange product(IntRange L, IntRange R) {
// If both LHS and RHS can be negative, we can form
// -2^L * -2^R = 2^(L + R)
// which requires L + R + 1 value bits to represent.
bool CanWiden = !L.NonNegative && !R.NonNegative;
bool Unsigned = L.NonNegative && R.NonNegative;
return IntRange(L.valueBits() + R.valueBits() + CanWiden + !Unsigned,
Unsigned);
}

/// Return the range of a remainder operation between the two ranges.
static IntRange rem(IntRange L, IntRange R) {
// The result of a remainder can't be larger than the result of
// either side. The sign of the result is the sign of the LHS.
bool Unsigned = L.NonNegative;
return IntRange(std::min(L.valueBits(), R.valueBits()) + !Unsigned,
Unsigned);
}
};

Expand Down Expand Up @@ -10325,9 +10382,13 @@ static QualType GetExprType(const Expr *E) {
/// Pseudo-evaluate the given integer expression, estimating the
/// range of values it might take.
///
/// \param MaxWidth - the width to which the value will be truncated
/// \param MaxWidth The width to which the value will be truncated.
/// \param Approximate If \c true, return a likely range for the result: in
/// particular, assume that aritmetic on narrower types doesn't leave
/// those types. If \c false, return a range including all possible
/// result values.
static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
bool InConstantContext) {
bool InConstantContext, bool Approximate) {
E = E->IgnoreParens();

// Try a full evaluation first.
Expand All @@ -10340,7 +10401,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// being of the new, wider type.
if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) {
if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
return GetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext);
return GetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext,
Approximate);

IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));

Expand All @@ -10353,7 +10415,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,

IntRange SubRange = GetExprRange(C, CE->getSubExpr(),
std::min(MaxWidth, OutputTypeRange.Width),
InConstantContext);
InConstantContext, Approximate);

// Bail out if the subexpr's range is as wide as the cast type.
if (SubRange.Width >= OutputTypeRange.Width)
Expand All @@ -10371,23 +10433,25 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
return GetExprRange(C,
CondResult ? CO->getTrueExpr() : CO->getFalseExpr(),
MaxWidth, InConstantContext);
MaxWidth, InConstantContext, Approximate);

// Otherwise, conservatively merge.
// GetExprRange requires an integer expression, but a throw expression
// results in a void type.
Expr *E = CO->getTrueExpr();
IntRange L = E->getType()->isVoidType()
? IntRange{0, true}
: GetExprRange(C, E, MaxWidth, InConstantContext);
: GetExprRange(C, E, MaxWidth, InConstantContext, Approximate);
E = CO->getFalseExpr();
IntRange R = E->getType()->isVoidType()
? IntRange{0, true}
: GetExprRange(C, E, MaxWidth, InConstantContext);
: GetExprRange(C, E, MaxWidth, InConstantContext, Approximate);
return IntRange::join(L, R);
}

if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
IntRange (*Combine)(IntRange, IntRange) = IntRange::join;

switch (BO->getOpcode()) {
case BO_Cmp:
llvm_unreachable("builtin <=> should have class type");
Expand Down Expand Up @@ -10419,7 +10483,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// been coerced to the LHS type.
case BO_Assign:
// TODO: bitfields?
return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
Approximate);

// Operations with opaque sources are black-listed.
case BO_PtrMemD:
Expand All @@ -10429,9 +10494,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// Bitwise-and uses the *infinum* of the two source ranges.
case BO_And:
case BO_AndAssign:
return IntRange::meet(
GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext),
GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext));
Combine = IntRange::bit_and;
break;

// Left shift gets black-listed based on a judgement call.
case BO_Shl:
Expand All @@ -10452,7 +10516,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// Right shift by a constant can narrow its left argument.
case BO_Shr:
case BO_ShrAssign: {
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext);
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext,
Approximate);

// If the shift amount is a positive constant, drop the width by
// that much.
Expand All @@ -10472,20 +10537,33 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,

// Comma acts as its right operand.
case BO_Comma:
return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
Approximate);

case BO_Add:
if (!Approximate)
Combine = IntRange::sum;
break;

// Black-list pointer subtractions.
case BO_Sub:
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forValueOfType(C, GetExprType(E));
if (!Approximate)
Combine = IntRange::difference;
break;

case BO_Mul:
if (!Approximate)
Combine = IntRange::product;
break;

// The width of a division result is mostly determined by the size
// of the LHS.
case BO_Div: {
// Don't 'pre-truncate' the operands.
unsigned opWidth = C.getIntWidth(GetExprType(E));
IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext);
IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext,
Approximate);

// If the divisor is constant, use that.
if (Optional<llvm::APSInt> divisor =
Expand All @@ -10499,36 +10577,35 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
}

// Otherwise, just use the LHS's width.
IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext);
// FIXME: This is wrong if the LHS could be its minimal value and the RHS
// could be -1.
IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext,
Approximate);
return IntRange(L.Width, L.NonNegative && R.NonNegative);
}

// The result of a remainder can't be larger than the result of
// either side.
case BO_Rem: {
// Don't 'pre-truncate' the operands.
unsigned opWidth = C.getIntWidth(GetExprType(E));
IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext);
IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext);

IntRange meet = IntRange::meet(L, R);
meet.Width = std::min(meet.Width, MaxWidth);
return meet;
}
case BO_Rem:
Combine = IntRange::rem;
break;

// The default behavior is okay for these.
case BO_Mul:
case BO_Add:
case BO_Xor:
case BO_Or:
break;
}

// The default case is to treat the operation as if it were closed
// on the narrowest type that encompasses both operands.
IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext);
IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
return IntRange::join(L, R);
// Combine the two ranges, but limit the result to the type in which we
// performed the computation.
QualType T = GetExprType(E);
unsigned opWidth = C.getIntWidth(T);
IntRange L =
GetExprRange(C, BO->getLHS(), opWidth, InConstantContext, Approximate);
IntRange R =
GetExprRange(C, BO->getRHS(), opWidth, InConstantContext, Approximate);
IntRange C = Combine(L, R);
C.NonNegative |= T->isUnsignedIntegerOrEnumerationType();
C.Width = std::min(C.Width, MaxWidth);
return C;
}

if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
Expand All @@ -10543,12 +10620,14 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
return IntRange::forValueOfType(C, GetExprType(E));

default:
return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext);
return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
}

if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
return GetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext);
return GetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext,
Approximate);

if (const auto *BitField = E->getSourceBitField())
return IntRange(BitField->getBitWidthValue(C),
Expand All @@ -10558,8 +10637,9 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
}

static IntRange GetExprRange(ASTContext &C, const Expr *E,
bool InConstantContext) {
return GetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext);
bool InConstantContext, bool Approximate) {
return GetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext,
Approximate);
}

/// Checks whether the given value, which currently has the given
Expand Down Expand Up @@ -10804,8 +10884,8 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType()))
return false;

IntRange OtherValueRange =
GetExprRange(S.Context, Other, S.isConstantEvaluated());
IntRange OtherValueRange = GetExprRange(
S.Context, Other, S.isConstantEvaluated(), /*Approximate*/ false);

QualType OtherT = Other->getType();
if (const auto *AT = OtherT->getAs<AtomicType>())
Expand Down Expand Up @@ -10849,6 +10929,11 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
}
}

// Don't warn if the non-constant operand actually always evaluates to the
// same value.
if (!TautologicalTypeCompare && OtherValueRange.Width == 0)
return false;

// Suppress the diagnostic for an in-range comparison if the constant comes
// from a macro or enumerator. We don't want to diagnose
//
Expand All @@ -10859,6 +10944,12 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
if (InRange && IsEnumConstOrFromMacro(S, Constant))
return false;

// A comparison of an unsigned bit-field against 0 is really a type problem,
// even though at the type level the bit-field might promote to 'signed int'.
if (Other->refersToBitField() && InRange && Value == 0 &&
Other->getType()->isUnsignedIntegerOrEnumerationType())
TautologicalTypeCompare = true;

// If this is a comparison to an enum constant, include that
// constant in the diagnostic.
const EnumConstantDecl *ED = nullptr;
Expand Down Expand Up @@ -11004,8 +11095,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
}

// Otherwise, calculate the effective range of the signed operand.
IntRange signedRange =
GetExprRange(S.Context, signedOperand, S.isConstantEvaluated());
IntRange signedRange = GetExprRange(
S.Context, signedOperand, S.isConstantEvaluated(), /*Approximate*/ true);

// Go ahead and analyze implicit conversions in the operands. Note
// that we skip the implicit conversions on both sides.
Expand All @@ -11023,7 +11114,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
if (E->isEqualityOp()) {
unsigned comparisonWidth = S.Context.getIntWidth(T);
IntRange unsignedRange =
GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated());
GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated(),
/*Approximate*/ true);

// We should never be unable to prove that the unsigned operand is
// non-negative.
Expand Down Expand Up @@ -11906,7 +11998,8 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
TargetBT->isFloatingType() && !IsListInit) {
// Determine the number of precision bits in the source integer type.
IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated(),
/*Approximate*/ true);
unsigned int SourcePrecision = SourceRange.Width;

// Determine the number of precision bits in the
Expand Down Expand Up @@ -11971,10 +12064,13 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
<< E->getType());
}

IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
IntRange MinSourceRange =
GetExprRange(S.Context, E, S.isConstantEvaluated(), /*Approximate*/ true);
IntRange MaxSourceRange =
GetExprRange(S.Context, E, S.isConstantEvaluated(), /*Approximate*/ false);
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);

if (SourceRange.Width > TargetRange.Width) {
if (MinSourceRange.Width > TargetRange.Width) {
// If the source is a constant, use a default-on diagnostic.
// TODO: this should happen for bitfield stores, too.
Expr::EvalResult Result;
Expand All @@ -11993,7 +12089,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
E->getExprLoc(), E,
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
<< E->getSourceRange() << clang::SourceRange(CC));
<< E->getSourceRange() << SourceRange(CC));
return;
}

Expand All @@ -12007,7 +12103,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision);
}

if (TargetRange.Width > SourceRange.Width) {
// Only warn here if E can't possibly reach the target range, not only if
// it's not likely to be in that range.
if (TargetRange.Width > MaxSourceRange.Width) {
if (auto *UO = dyn_cast<UnaryOperator>(E))
if (UO->getOpcode() == UO_Minus)
if (Source->isUnsignedIntegerType()) {
Expand All @@ -12020,8 +12118,8 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}

if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative &&
SourceRange.NonNegative && Source->isSignedIntegerType()) {
if (TargetRange.Width == MinSourceRange.Width && !TargetRange.NonNegative &&
MinSourceRange.NonNegative && Source->isSignedIntegerType()) {
// Warn when doing a signed to signed conversion, warn if the positive
// source value is exactly the width of the target type, which will
// cause a negative value to be stored.
Expand All @@ -12038,17 +12136,17 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
E->getExprLoc(), E,
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
<< E->getSourceRange() << clang::SourceRange(CC));
<< E->getSourceRange() << SourceRange(CC));
return;
}
}

// Fall through for non-constants to give a sign conversion warning.
}

if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
(!TargetRange.NonNegative && SourceRange.NonNegative &&
SourceRange.Width == TargetRange.Width)) {
if ((TargetRange.NonNegative && !MinSourceRange.NonNegative) ||
(!TargetRange.NonNegative && MinSourceRange.NonNegative &&
MinSourceRange.Width == TargetRange.Width)) {
if (S.SourceMgr.isInSystemMacro(CC))
return;

Expand Down
14 changes: 14 additions & 0 deletions clang/test/Sema/compare.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ int test5(unsigned int x) {
&& (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}}
}

struct bitfield {
int a : 3;
unsigned b : 3;
long c : 40;
unsigned long d : 40;
};

void test5a(struct bitfield a) {
if (a.a < 0) {}
if (a.b < 0) {} // expected-warning {{comparison of unsigned expression < 0 is always false}}
if (a.c < 0) {}
if (a.d < 0) {} // expected-warning {{comparison of unsigned expression < 0 is always false}}
}

int test6(unsigned i, unsigned power) {
unsigned x = (i < (1 << power) ? i : 0);
return x != 3 ? 1 << power : i;
Expand Down
116 changes: 99 additions & 17 deletions clang/test/Sema/tautological-constant-compare.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtautological-type-limit-compare -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtype-limits -DTEST -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtype-limits -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -verify=silent %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -verify=silent -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify=silent %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify=silent -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify=silent %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify=silent -x c++ %s

#ifndef TEST
// silent-no-diagnostics
#endif

int value(void);

Expand Down Expand Up @@ -184,7 +188,6 @@ int main()
if (-32768L >= s)
return 0;
#else
// expected-no-diagnostics
if (s == 32767)
return 0;
if (s != 32767)
Expand Down Expand Up @@ -373,7 +376,6 @@ int main()
if (65535UL >= us) // expected-warning {{comparison 65535 >= 'unsigned short' is always true}}
return 0;
#else
// expected-no-diagnostics
if (us == 65535)
return 0;
if (us != 65535)
Expand Down Expand Up @@ -571,20 +573,100 @@ int main()

if ((s & 0xff) < 0) {} // #valuerange1
if ((s & 0xff) < 1) {}
if ((s & -3) < -4) {} // #valuerange2
if ((s & -3) < -4) {}
if ((s & -3) < -3) {}
if ((s & -3) < 4u) {} // (true if s non-negative)
if ((s & -3) > 4u) {} // (true if s negative)
if ((s & -3) == 4u) {} // #valuerange3 (never true)
if ((s & -3) == 3u) {}
if ((s & -3) == -5u) {} // #valuerange4
if ((s & -3) < 4u) {}
if ((s & -3) > 4u) {}
if ((s & -3) == 4u) {}
if ((s & -3) == 3u) {} // FIXME: Impossible.
if ((s & -3) == -5u) {}
if ((s & -3) == -4u) {}
#if TEST == 2
// expected-warning@#valuerange1 {{comparison of 8-bit unsigned value < 0 is always false}}
// expected-warning@#valuerange2 {{comparison of 3-bit signed value < -4 is always false}}
// expected-warning@#valuerange3 {{comparison of 3-bit signed value == 4 is always false}}
// expected-warning@#valuerange4 {{comparison of 3-bit signed value == 4294967291 is always false}}
#endif

// FIXME: Our bit-level width tracking comes unstuck here: the second of the
// conditions below is also tautological, but we can't tell that because we
// don't track the actual range, only the bit-width.
if ((s ? 1 : 0) + (us ? 1 : 0) > 1) {}
if ((s ? 1 : 0) + (us ? 1 : 0) > 2) {}
if ((s ? 1 : 0) + (us ? 1 : 0) > 3) {} // #addrange1
#if TEST == 2
// expected-warning@#addrange1 {{comparison of 2-bit unsigned value > 3 is always false}}
#endif

// FIXME: The second and third comparisons are also tautological; 0x40000000
// is the greatest value that multiplying two int16s can produce.
if (s * s > 0x3fffffff) {}
if (s * s > 0x40000000) {}
if (s * s > 0x7ffffffe) {}
if (s * s > 0x7fffffff) {} // expected-warning {{result of comparison 'int' > 2147483647 is always false}}

if ((s & 0x3ff) * (s & 0x1f) > 0x7be0) {}
if ((s & 0x3ff) * (s & 0x1f) > 0x7be1) {} // FIXME
if ((s & 0x3ff) * (s & 0x1f) > 0x7ffe) {} // FIXME
if ((s & 0x3ff) * (s & 0x1f) > 0x7fff) {} // #mulrange1
#if TEST == 2
// expected-warning@#mulrange1 {{comparison of 15-bit unsigned value > 32767 is always false}}
#endif

if (a.a * a.b > 21) {} // FIXME
if (a.a * a.b > 31) {} // #mulrange2
#if TEST == 2
// expected-warning@#mulrange2 {{comparison of 6-bit signed value > 31 is always false}}
#endif

if (a.a - (s & 1) < -4) {}
if (a.a - (s & 1) < -7) {} // FIXME
if (a.a - (s & 1) < -8) {} // #subrange1
if (a.a - (s & 1) > 3) {} // FIXME: Can be < -4 but not > 3.
if (a.a - (s & 1) > 7) {} // #subrange2

if (a.a - (s & 7) < -8) {}
if (a.a - (s & 7) > 7) {} // FIXME: Can be < -8 but not > 7.
if (a.a - (s & 7) < -15) {}
if (a.a - (s & 7) < -16) {} // #subrange3
if (a.a - (s & 7) > 15) {} // #subrange4

if (a.b - (s & 1) > 6) {}
if (a.b - (s & 1) > 7) {} // #subrange5
if (a.b - (s & 7) < -8) {} // #subrange6
if (a.b - (s & 15) < -8) {}
if (a.b - (s & 15) < -16) {} // #subrange7
#if TEST == 2
// expected-warning@#subrange1 {{comparison of 4-bit signed value < -8 is always false}}
// expected-warning@#subrange2 {{comparison of 4-bit signed value > 7 is always false}}
// expected-warning@#subrange3 {{comparison of 5-bit signed value < -16 is always false}}
// expected-warning@#subrange4 {{comparison of 5-bit signed value > 15 is always false}}
// expected-warning@#subrange5 {{comparison of 4-bit signed value > 7 is always false}}
// expected-warning@#subrange6 {{comparison of 4-bit signed value < -8 is always false}}
// expected-warning@#subrange7 {{comparison of 5-bit signed value < -16 is always false}}
#endif

// a.a % 3 is in range [-2, 2], which we expand to [-4, 4)
if (a.a % 3 > 2) {}
if (a.a % 3 > 3) {} // #remrange1
if (a.a % 3 == -1) {}
if (a.a % 3 == -2) {}
if (a.a % 3 < -3) {} // FIXME
if (a.a % 3 < -4) {} // #remrange2

// a.b % 3 is in range [0, 3), which we expand to [0, 4)
if (a.b % 3 > 2) {}
if (a.b % 3 > 3) {} // #remrange3
if (a.b % 3 < 0) {} // #remrange4
#if TEST == 2
// expected-warning@#remrange1 {{comparison of 3-bit signed value > 3 is always false}}
// expected-warning@#remrange2 {{comparison of 3-bit signed value < -4 is always false}}
// expected-warning@#remrange3 {{comparison of 2-bit unsigned value > 3 is always false}}
// expected-warning@#remrange4 {{comparison of 2-bit unsigned value < 0 is always false}}
#endif

// Don't warn on non-constant-expression values that end up being a constant
// 0; we generally only want to warn when one side of the comparison is
// effectively non-constant.
if ("x"[1] == 0) {}
if (((void)s, 0) == 0) {}

return 1;
}