[cfe-commits] [PATCH] Improve -Wtautological-constant-out-of-range-compare

Eli Friedman eli.friedman at gmail.com
Mon Nov 12 11:22:09 PST 2012


Comments below.

On Mon, Nov 12, 2012 at 9:46 AM, Richard Trieu <rtrieu at google.com> wrote:
> Make -Wtautological-constant-out-of-range-compare checking take into account types and conversion between types.  The old version merely checked the bit widths, which allowed failed to catch a few cases, while warning on other safe comparisons.
>
> http://llvm-reviews.chandlerc.com/D113
>
> Files:
>   test/Analysis/additive-folding.cpp
>   test/SemaCXX/compare.cpp
>   test/SemaCXX/warn-enum-compare.cpp
>   lib/Sema/SemaChecking.cpp

Index: test/SemaCXX/warn-enum-compare.cpp
===================================================================
--- test/SemaCXX/warn-enum-compare.cpp
+++ test/SemaCXX/warn-enum-compare.cpp
@@ -39,8 +39,8 @@
   while (b == c);
   while (B1 == name1::B2);
   while (B2 == name2::B1);
-  while (x == AnonAA); // expected-warning {{comparison of constant
42 with expression of type 'Foo' is always false}}
-  while (AnonBB == y); // expected-warning {{comparison of constant
45 with expression of type 'Bar' is always false}}
+  while (x == AnonAA);
+  while (AnonBB == y);
   while (AnonAA == AnonAB);
   while (AnonAB == AnonBA);
   while (AnonBB == AnonAA);

Why are you changing this warning?

   while (AnonBB == AnonAA);
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -4328,38 +4328,91 @@
                                          Expr *Constant, Expr *Other,
                                          llvm::APSInt Value,
                                          bool RhsConstant) {
+  // 0 values are handled later by CheckTrivialUnsignedComparison().
+  if (Value == 0)
+    return;
+
   BinaryOperatorKind op = E->getOpcode();
   QualType OtherT = Other->getType();
   QualType ConstantT = Constant->getType();
+  QualType CommonT = E->getLHS()->getType();
   if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
     return;
   assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
          && "comparison with non-integer type");
   // FIXME. handle cases for signedness to catch (signed char)N == 200

Does this patch fix this FIXME?

-  IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
-  IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
-  if (OtherRange.Width >= LitRange.Width)
+
+  bool ConstantSigned = ConstantT->isSignedIntegerType();
+  bool OtherSigned = OtherT->isSignedIntegerType();
+  bool CommonSigned = CommonT->isSignedIntegerType();

Why are you getting rid of the IntRange usage?  Granted, we didn't
really have any good testcases, but it does add power to the analysis
in some cases.

+  bool EqualityOnly = false;
+
+  if (CommonSigned) {
+    // The common type is signed, therefore no signed to unsigned conversion.
+    if (OtherSigned) {
+      // Check that the constant is representable in type OtherT.
+      if (S.Context.getIntWidth(OtherT) >= Value.getMinSignedBits())

Calling getMinSignedBits() on an unsigned constant will do the wrong
thing in cases like 0xFFFFFFFFU.  (I'm not sure it's actually possible
to write a testcase where this matters, but it would make more sense
anyway.)

+        return;
+    } else { // !OtherSigned
+      // Check that the constant is representable in type OtherT.
+      // Negative values are out of range.
+      if (Value.isNonNegative() &&
+          S.Context.getIntWidth(OtherT) >= Value.getActiveBits())

Calling isNonNegative() on an unsigned constant can also do the wrong thing.

.+        return;
+    }
+  } else {  // !CommonSigned
+    if (!OtherSigned && !ConstantSigned) {
+      // Both types are unsigned, check the constant is representable in
+      // type OtherT.
+      if (S.Context.getIntWidth(OtherT) >= Value.getActiveBits())
+        return;
+    } else if (!OtherSigned && ConstantSigned) {
+      if (S.Context.getIntWidth(OtherT) >= Value.getActiveBits())
+        return;

Calling getActiveBits() on a signed value is suspicious; the return
will vary with the width of the constant for the same value.

+    } else if (OtherSigned && !ConstantSigned) {
+      // Check to see if the constant is representable in OtherT.
+      if (S.Context.getIntWidth(OtherT) > Value.getActiveBits())
+        return;
+      // Check to see if the constant is equivalent to a negative value
+      // cast to CommonT.
+      if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
+          Value.isNegative() &&

Is this going to handle cases like (int)x == 0xFFFFFFFFFFFFFFFFULL correctly?

-Eli



More information about the cfe-commits mailing list