For now, I've undone the change that caused us to warn (ever!) on comparisons between two expressions of enumeration type, and also the change to use more precise bit-width information for bit-field comparisons, and re-committed as r320211.
The bugs exposed by self-host have been fixed in r320212 and r320206. On 8 December 2017 at 14:09, Richard Smith <rich...@metafoo.co.uk> wrote: > Selfhost failures are ultimately caused by: > > https://github.com/llvm-mirror/llvm/blob/master/utils/ > TableGen/X86RecognizableInstr.cpp#L709 > https://github.com/llvm-mirror/clang/blob/master/include/clang/AST/ > OperationKinds.h#L26 > > These are genuine bugs: assigning -1 into an enumeration with no negative > enumerators results in undefined behavior. We should probably have a > warning for the casts here rather than only detecting the problem under > -Wtautological-compare, but I would not be surprised to find that Clang > miscompiles itself with -fstrict-enums due to the above two issues. > > On 8 December 2017 at 13:40, Hans Wennborg via cfe-commits < > cfe-commits@lists.llvm.org> wrote: > >> For what it's worth, Chromium's bitfield warning is easy to fix. The >> "-1 vs enum" comparisons are more plentiful and less straightforward. >> I'm guessing it's the same for the self-host. >> >> On Fri, Dec 8, 2017 at 1:33 PM, Richard Smith via cfe-commits >> <cfe-commits@lists.llvm.org> wrote: >> > I'm going to reland without the changes to bit-field handling. If we >> want >> > those changes (which I think we do, based on the bugs it found in >> selfhost), >> > that'll need to be done more carefully, and I don't want to get the >> > refactoring and bugfixes here tangled up with that. >> > >> > On 8 December 2017 at 13:27, Bill Seurer via cfe-commits >> > <cfe-commits@lists.llvm.org> wrote: >> >> >> >> It also caused all the sanitizer builds to fail. For example: >> >> >> >> http://lab.llvm.org:8011/builders/sanitizer-ppc64le-linux/builds/3654 >> >> >> >> >> >> /home/buildbots/ppc64le-sanitizer/sanitizer-ppc64le/build/ >> llvm/utils/TableGen/X86RecognizableInstr.cpp:789:21: >> >> error: comparison of constant -1 with expression of type >> >> 'llvm::X86Disassembler::OpcodeType' is always true >> >> [-Werror,-Wtautological-constant-out-of-range-compare] >> >> assert(opcodeType != (OpcodeType)-1 && >> >> ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~ >> >> /usr/include/assert.h:86:5: note: expanded from macro 'assert' >> >> ((expr) >> \ >> >> ^~~~ >> >> 1 error generated. >> >> utils/TableGen/CMakeFiles/obj.llvm-tblgen.dir/build.make:1022: recipe >> for >> >> target >> >> 'utils/TableGen/CMakeFiles/obj.llvm-tblgen.dir/X86Recognizab >> leInstr.cpp.o' >> >> failed >> >> make[3]: *** >> >> [utils/TableGen/CMakeFiles/obj.llvm-tblgen.dir/X86Recognizab >> leInstr.cpp.o] >> >> Error 1 >> >> >> >> >> >> >> >> And there are lots more warnings (which are flagged as errors for the >> >> sanitizer builds) when I run a build by hand. For example: >> >> >> >> [4001/4008] Building CXX object >> >> tools/clang/tools/libclang/CMakeFiles/libclang.dir/CIndex.cpp.o >> >> In file included from >> >> /home/seurer/llvm/llvm-test2/tools/clang/tools/libclang/CIndex.cpp:23: >> >> In file included from >> >> /home/seurer/llvm/llvm-test2/tools/clang/tools/libclang/Curs >> orVisitor.h:16: >> >> In file included from >> >> /home/seurer/llvm/llvm-test2/tools/clang/include/clang/AST/D >> eclVisitor.h:19: >> >> In file included from >> >> /home/seurer/llvm/llvm-test2/tools/clang/include/clang/AST/D >> eclCXX.h:21: >> >> In file included from >> >> /home/seurer/llvm/llvm-test2/tools/clang/include/clang/AST/Attr.h:19: >> >> /home/seurer/llvm/llvm-test2/tools/clang/include/clang/AST/E >> xpr.h:2745:17: >> >> warning: comparison of constant -1 with expression of type 'const >> >> clang::CastKind' is always true >> >> [-Wtautological-constant-out-of-range-compare] >> >> assert(kind != CK_Invalid && "creating cast with invalid cast >> kind"); >> >> ~~~~ ^ ~~~~~~~~~~ >> >> /usr/include/assert.h:89:5: note: expanded from macro 'assert' >> >> ((expr) >> \ >> >> ^~~~ >> >> >> >> >> >> >> >> On 12/08/2017 10:54 AM, Hans Wennborg via cfe-commits wrote: >> >>> >> >>> Author: hans >> >>> Date: Fri Dec 8 08:54:08 2017 >> >>> New Revision: 320162 >> >>> >> >>> URL: http://llvm.org/viewvc/llvm-project?rev=320162&view=rev >> >>> Log: >> >>> Revert "Unify implementation of our two different flavours of >> >>> -Wtautological-compare." >> >>> >> >>>> Unify implementation of our two different flavours of >> >>>> -Wtautological-compare. >> >>>> >> >>>> In so doing, fix a handful of remaining bugs where we would report >> false >> >>>> positives or false negatives if we promote a signed value to an >> unsigned >> >>>> type >> >>>> for the comparison. >> >>> >> >>> >> >>> This caused a new warning in Chromium: >> >>> >> >>> ../../base/trace_event/trace_log.cc:1545:29: error: comparison of >> >>> constant 64 >> >>> with expression of type 'unsigned int' is always true >> >>> [-Werror,-Wtautological-constant-out-of-range-compare] >> >>> DCHECK(handle.event_index < TraceBufferChunk::kTraceBuffer >> ChunkSize); >> >>> ~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> ~~~~~~~~~ >> >>> >> >>> The 'unsigned int' is really a 6-bit bitfield, which is why it's >> always >> >>> less than 64. >> >>> >> >>> I thought we didn't use to warn (with out-of-range-compare) when >> >>> comparing >> >>> against the boundaries of a type? >> >>> >> >>> Modified: >> >>> cfe/trunk/lib/Sema/SemaChecking.cpp >> >>> cfe/trunk/test/Sema/tautological-constant-compare.c >> >>> cfe/trunk/test/Sema/tautological-constant-enum-compare.c >> >>> cfe/trunk/test/SemaCXX/compare.cpp >> >>> >> >>> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp >> >>> URL: >> >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaC >> hecking.cpp?rev=320162&r1=320161&r2=320162&view=diff >> >>> >> >>> ============================================================ >> ================== >> >>> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) >> >>> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Dec 8 08:54:08 2017 >> >>> @@ -8662,113 +8662,54 @@ static bool isKnownToHaveUnsignedValue(E >> >>> } >> >>> namespace { >> >>> -/// The promoted range of values of a type. In general this has the >> >>> -/// following structure: >> >>> -/// >> >>> -/// |-----------| . . . |-----------| >> >>> -/// ^ ^ ^ ^ >> >>> -/// Min HoleMin HoleMax Max >> >>> -/// >> >>> -/// ... where there is only a hole if a signed type is promoted to >> >>> unsigned >> >>> -/// (in which case Min and Max are the smallest and largest >> >>> representable >> >>> -/// values). >> >>> -struct PromotedRange { >> >>> - // Min, or HoleMax if there is a hole. >> >>> - llvm::APSInt PromotedMin; >> >>> - // Max, or HoleMin if there is a hole. >> >>> - llvm::APSInt PromotedMax; >> >>> - >> >>> - PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) { >> >>> - if (R.Width == 0) >> >>> - PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned); >> >>> - else { >> >>> - PromotedMin = llvm::APSInt::getMinValue(R.Width, >> R.NonNegative) >> >>> - .extOrTrunc(BitWidth); >> >>> - PromotedMin.setIsUnsigned(Unsigned); >> >>> - >> >>> - PromotedMax = llvm::APSInt::getMaxValue(R.Width, >> R.NonNegative) >> >>> - .extOrTrunc(BitWidth); >> >>> - PromotedMax.setIsUnsigned(Unsigned); >> >>> - } >> >>> - } >> >>> - // Determine whether this range is contiguous (has no hole). >> >>> - bool isContiguous() const { return PromotedMin <= PromotedMax; } >> >>> +enum class LimitType { >> >>> + Max = 1U << 0U, // e.g. 32767 for short >> >>> + Min = 1U << 1U, // e.g. -32768 for short >> >>> + Both = Max | Min // When the value is both the Min and the Max >> limit >> >>> at the >> >>> + // same time; e.g. in C++, A::a in enum A { a = 0 >> }; >> >>> +}; >> >>> - // Where a constant value is within the range. >> >>> - enum ComparisonResult { >> >>> - LT = 0x1, >> >>> - LE = 0x2, >> >>> - GT = 0x4, >> >>> - GE = 0x8, >> >>> - EQ = 0x10, >> >>> - NE = 0x20, >> >>> - InRangeFlag = 0x40, >> >>> - >> >>> - Less = LE | LT | NE, >> >>> - Min = LE | InRangeFlag, >> >>> - InRange = InRangeFlag, >> >>> - Max = GE | InRangeFlag, >> >>> - Greater = GE | GT | NE, >> >>> +} // namespace >> >>> - OnlyValue = LE | GE | EQ | InRangeFlag, >> >>> - InHole = NE >> >>> - }; >> >>> +/// Checks whether Expr 'Constant' may be the >> >>> +/// std::numeric_limits<>::max() or std::numeric_limits<>::min() >> >>> +/// of the Expr 'Other'. If true, then returns the limit type (min or >> >>> max). >> >>> +/// The Value is the evaluation of Constant >> >>> +static llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, >> >>> + Expr *Other, >> >>> + const llvm::APSInt >> &Value) >> >>> { >> >>> + if (IsEnumConstOrFromMacro(S, Constant)) >> >>> + return llvm::Optional<LimitType>(); >> >>> - ComparisonResult compare(const llvm::APSInt &Value) const { >> >>> - assert(Value.getBitWidth() == PromotedMin.getBitWidth() && >> >>> - Value.isUnsigned() == PromotedMin.isUnsigned()); >> >>> - if (!isContiguous()) { >> >>> - assert(Value.isUnsigned() && "discontiguous range for signed >> >>> compare"); >> >>> - if (Value.isMinValue()) return Min; >> >>> - if (Value.isMaxValue()) return Max; >> >>> - if (Value >= PromotedMin) return InRange; >> >>> - if (Value <= PromotedMax) return InRange; >> >>> - return InHole; >> >>> - } >> >>> + if (isKnownToHaveUnsignedValue(Other) && Value == 0) >> >>> + return LimitType::Min; >> >>> - switch (llvm::APSInt::compareValues(Value, PromotedMin)) { >> >>> - case -1: return Less; >> >>> - case 0: return PromotedMin == PromotedMax ? OnlyValue : Min; >> >>> - case 1: >> >>> - switch (llvm::APSInt::compareValues(Value, PromotedMax)) { >> >>> - case -1: return InRange; >> >>> - case 0: return Max; >> >>> - case 1: return Greater; >> >>> - } >> >>> - } >> >>> + // TODO: Investigate using GetExprRange() to get tighter bounds >> >>> + // on the bit ranges. >> >>> + QualType OtherT = Other->IgnoreParenImpCasts()->getType(); >> >>> + if (const auto *AT = OtherT->getAs<AtomicType>()) >> >>> + OtherT = AT->getValueType(); >> >>> - llvm_unreachable("impossible compare result"); >> >>> - } >> >>> + IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); >> >>> + if (Other->isKnownToHaveBooleanValue()) >> >>> + OtherRange = IntRange::forBoolType(); >> >>> - static llvm::Optional<bool> constantValue(BinaryOperatorKind Op, >> >>> - ComparisonResult R, >> >>> - bool ConstantOnRHS) { >> >>> - ComparisonResult TrueFlag, FalseFlag; >> >>> - if (Op == BO_EQ) { >> >>> - TrueFlag = EQ; >> >>> - FalseFlag = NE; >> >>> - } else if (Op == BO_NE) { >> >>> - TrueFlag = NE; >> >>> - FalseFlag = EQ; >> >>> - } else { >> >>> - if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) { >> >>> - TrueFlag = LT; >> >>> - FalseFlag = GE; >> >>> - } else { >> >>> - TrueFlag = GT; >> >>> - FalseFlag = LE; >> >>> - } >> >>> - if (Op == BO_GE || Op == BO_LE) >> >>> - std::swap(TrueFlag, FalseFlag); >> >>> - } >> >>> - if (R & TrueFlag) >> >>> - return true; >> >>> - if (R & FalseFlag) >> >>> - return false; >> >>> - return llvm::None; >> >>> - } >> >>> -}; >> >>> + // Special-case for C++ for enum with one enumerator with value of >> 0. >> >>> + if (OtherRange.Width == 0) >> >>> + return Value == 0 ? LimitType::Both : >> llvm::Optional<LimitType>(); >> >>> + >> >>> + if (llvm::APSInt::isSameValue( >> >>> + llvm::APSInt::getMaxValue(OtherRange.Width, >> >>> OtherRange.NonNegative), >> >>> + Value)) >> >>> + return LimitType::Max; >> >>> + >> >>> + if (llvm::APSInt::isSameValue( >> >>> + llvm::APSInt::getMinValue(OtherRange.Width, >> >>> OtherRange.NonNegative), >> >>> + Value)) >> >>> + return LimitType::Min; >> >>> + >> >>> + return llvm::None; >> >>> } >> >>> static bool HasEnumType(Expr *E) { >> >>> @@ -8806,47 +8747,29 @@ static bool CheckTautologicalComparison( >> >>> if (S.inTemplateInstantiation() || !E->isRelationalOp()) >> >>> return false; >> >>> - if (IsEnumConstOrFromMacro(S, Constant)) >> >>> - return false; >> >>> - >> >>> - Expr *OriginalOther = Other; >> >>> + BinaryOperatorKind Op = E->getOpcode(); >> >>> - Constant = Constant->IgnoreParenImpCasts(); >> >>> - Other = Other->IgnoreParenImpCasts(); >> >>> - >> >>> - // TODO: Investigate using GetExprRange() to get tighter bounds >> >>> - // on the bit ranges. >> >>> - QualType OtherT = Other->getType(); >> >>> - if (const auto *AT = OtherT->getAs<AtomicType>()) >> >>> - OtherT = AT->getValueType(); >> >>> - IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); >> >>> - >> >>> - // Whether we're treating Other as being a bool because of the >> form of >> >>> - // expression despite it having another type (typically 'int' in >> C). >> >>> - bool OtherIsBooleanDespiteType = >> >>> - !OtherT->isBooleanType() && Other->isKnownToHaveBooleanVal >> ue(); >> >>> - if (OtherIsBooleanDespiteType) >> >>> - OtherRange = IntRange::forBoolType(); >> >>> - >> >>> - if (FieldDecl *Bitfield = Other->getSourceBitField()) >> >>> - if (!Bitfield->getBitWidth()->isValueDependent()) >> >>> - OtherRange.Width = >> >>> - std::min(Bitfield->getBitWidthValue(S.Context), >> >>> OtherRange.Width); >> >>> - >> >>> - // Check whether the constant value can be represented in >> OtherRange. >> >>> Bail >> >>> - // out if so; this isn't an out-of-range comparison. >> >>> - PromotedRange OtherPromotedRange(OtherRange, Value.getBitWidth(), >> >>> - Value.isUnsigned()); >> >>> - >> >>> - auto Cmp = OtherPromotedRange.compare(Value); >> >>> - if (Cmp != PromotedRange::Min && Cmp != PromotedRange::Max && >> >>> - Cmp != PromotedRange::OnlyValue) >> >>> + QualType OType = Other->IgnoreParenImpCasts()->getType(); >> >>> + if (!OType->isIntegerType()) >> >>> return false; >> >>> - auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, >> >>> RhsConstant); >> >>> - if (!Result) >> >>> + // Determine which limit (min/max) the constant is, if either. >> >>> + llvm::Optional<LimitType> ValueType = IsTypeLimit(S, Constant, >> Other, >> >>> Value); >> >>> + if (!ValueType) >> >>> return false; >> >>> + bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ >> RhsConstant; >> >>> + bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE); >> >>> + if (ValueType != LimitType::Both) { >> >>> + bool ResultWhenConstNeOther = >> >>> + ConstIsLowerBound ^ (ValueType == LimitType::Max); >> >>> + if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) >> >>> + return false; // The comparison is not tautological. >> >>> + } else if (ResultWhenConstEqualsOther == ConstIsLowerBound) >> >>> + return false; // The comparison is not tautological. >> >>> + >> >>> + const bool Result = ResultWhenConstEqualsOther; >> >>> + >> >>> // Should be enough for uint128 (39 decimal digits) >> >>> SmallString<64> PrettySourceValue; >> >>> llvm::raw_svector_ostream OS(PrettySourceValue); >> >>> @@ -8859,20 +8782,20 @@ static bool CheckTautologicalComparison( >> >>> S.DiagRuntimeBehavior( >> >>> E->getOperatorLoc(), E, >> >>> S.PDiag(diag::warn_tautological_bool_compare) >> >>> - << OS.str() << classifyConstantValue(Constant) >> >>> - << OtherT << !OtherT->isBooleanType() << *Result >> >>> + << OS.str() << >> >>> classifyConstantValue(Constant->IgnoreParenImpCasts()) >> >>> + << OType << !OType->isBooleanType() << Result >> >>> << E->getLHS()->getSourceRange() << >> >>> E->getRHS()->getSourceRange()); >> >>> return true; >> >>> } >> >>> - unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && >> Value >> >>> == 0) >> >>> - ? (HasEnumType(OriginalOther) >> >>> + unsigned Diag = (isKnownToHaveUnsignedValue(Other) && Value == 0) >> >>> + ? (HasEnumType(Other) >> >>> ? >> >>> diag::warn_unsigned_enum_always_true_comparison >> >>> : >> >>> diag::warn_unsigned_always_true_comparison) >> >>> : diag::warn_tautological_constant_compare; >> >>> S.Diag(E->getOperatorLoc(), Diag) >> >>> - << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << >> >>> *Result >> >>> + << RhsConstant << OType << E->getOpcodeStr() << OS.str() << >> Result >> >>> << E->getLHS()->getSourceRange() << >> >>> E->getRHS()->getSourceRange(); >> >>> return true; >> >>> @@ -8894,6 +8817,7 @@ static bool DiagnoseOutOfRangeComparison >> >>> QualType OtherT = Other->getType(); >> >>> if (const auto *AT = OtherT->getAs<AtomicType>()) >> >>> OtherT = AT->getValueType(); >> >>> + >> >>> IntRange OtherRange = IntRange::forValueOfType(S.Context, >> OtherT); >> >>> // Whether we're treating Other as being a bool because of the >> form >> >>> of >> >>> @@ -8903,25 +8827,91 @@ static bool DiagnoseOutOfRangeComparison >> >>> if (OtherIsBooleanDespiteType) >> >>> OtherRange = IntRange::forBoolType(); >> >>> - if (FieldDecl *Bitfield = Other->getSourceBitField()) >> >>> - if (!Bitfield->getBitWidth()->isValueDependent()) >> >>> - OtherRange.Width = >> >>> - std::min(Bitfield->getBitWidthValue(S.Context), >> >>> OtherRange.Width); >> >>> + unsigned OtherWidth = OtherRange.Width; >> >>> + >> >>> + BinaryOperatorKind op = E->getOpcode(); >> >>> + bool IsTrue = true; >> >>> // Check whether the constant value can be represented in >> >>> OtherRange. Bail >> >>> // out if so; this isn't an out-of-range comparison. >> >>> - PromotedRange OtherPromotedRange(OtherRange, Value.getBitWidth(), >> >>> - Value.isUnsigned()); >> >>> - auto Cmp = OtherPromotedRange.compare(Value); >> >>> - >> >>> - // If Value is in the range of possible Other values, this >> comparison >> >>> is not >> >>> - // tautological. >> >>> - if (Cmp & PromotedRange::InRangeFlag) >> >>> - return false; >> >>> + { >> >>> + QualType ConstantT = Constant->getType(); >> >>> + QualType CommonT = E->getLHS()->getType(); >> >>> - auto IsTrue = PromotedRange::constantValue(E->getOpcode(), Cmp, >> >>> RhsConstant); >> >>> - if (!IsTrue) >> >>> - return false; >> >>> + if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT) && >> >>> + !OtherIsBooleanDespiteType) >> >>> + return false; >> >>> + assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) >> && >> >>> + "comparison with non-integer type"); >> >>> + >> >>> + bool ConstantSigned = ConstantT->isSignedIntegerType(); >> >>> + bool CommonSigned = CommonT->isSignedIntegerType(); >> >>> + >> >>> + bool EqualityOnly = false; >> >>> + >> >>> + if (CommonSigned) { >> >>> + // The common type is signed, therefore no signed to unsigned >> >>> conversion. >> >>> + if (!OtherRange.NonNegative) { >> >>> + // Check that the constant is representable in type OtherT. >> >>> + if (ConstantSigned) { >> >>> + if (OtherWidth >= Value.getMinSignedBits()) >> >>> + return false; >> >>> + } else { // !ConstantSigned >> >>> + if (OtherWidth >= Value.getActiveBits() + 1) >> >>> + return false; >> >>> + } >> >>> + } else { // !OtherSigned >> >>> + // Check that the constant is representable in type >> >>> OtherT. >> >>> + // Negative values are out of range. >> >>> + if (ConstantSigned) { >> >>> + if (Value.isNonNegative() && OtherWidth >= >> >>> Value.getActiveBits()) >> >>> + return false; >> >>> + } else { // !ConstantSigned >> >>> + if (OtherWidth >= Value.getActiveBits()) >> >>> + return false; >> >>> + } >> >>> + } >> >>> + } else { // !CommonSigned >> >>> + if (OtherRange.NonNegative) { >> >>> + if (OtherWidth >= Value.getActiveBits()) >> >>> + return false; >> >>> + } else { // OtherSigned >> >>> + assert(!ConstantSigned && >> >>> + "Two signed types converted to unsigned types."); >> >>> + // Check to see if the constant is representable in OtherT. >> >>> + if (OtherWidth > Value.getActiveBits()) >> >>> + return false; >> >>> + // 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() && Value.getMinSignedBits() <= >> >>> OtherWidth) >> >>> + return false; >> >>> + // The constant value rests between values that OtherT can >> >>> represent >> >>> + // after conversion. Relational comparison still works, but >> >>> equality >> >>> + // comparisons will be tautological. >> >>> + EqualityOnly = true; >> >>> + } >> >>> + } >> >>> + >> >>> + bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); >> >>> + >> >>> + if (op == BO_EQ || op == BO_NE) { >> >>> + IsTrue = op == BO_NE; >> >>> + } else if (EqualityOnly) { >> >>> + return false; >> >>> + } else if (RhsConstant) { >> >>> + if (op == BO_GT || op == BO_GE) >> >>> + IsTrue = !PositiveConstant; >> >>> + else // op == BO_LT || op == BO_LE >> >>> + IsTrue = PositiveConstant; >> >>> + } else { >> >>> + if (op == BO_LT || op == BO_LE) >> >>> + IsTrue = !PositiveConstant; >> >>> + else // op == BO_GT || op == BO_GE >> >>> + IsTrue = PositiveConstant; >> >>> + } >> >>> + } >> >>> // If this is a comparison to an enum constant, include that >> >>> // constant in the diagnostic. >> >>> @@ -8940,7 +8930,7 @@ static bool DiagnoseOutOfRangeComparison >> >>> E->getOperatorLoc(), E, >> >>> S.PDiag(diag::warn_out_of_range_compare) >> >>> << OS.str() << classifyConstantValue(Constant) >> >>> - << OtherT << OtherIsBooleanDespiteType << *IsTrue >> >>> + << OtherT << OtherIsBooleanDespiteType << IsTrue >> >>> << E->getLHS()->getSourceRange() << >> >>> E->getRHS()->getSourceRange()); >> >>> return true; >> >>> >> >>> Modified: cfe/trunk/test/Sema/tautological-constant-compare.c >> >>> URL: >> >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/taut >> ological-constant-compare.c?rev=320162&r1=320161&r2=320162&view=diff >> >>> >> >>> ============================================================ >> ================== >> >>> --- cfe/trunk/test/Sema/tautological-constant-compare.c (original) >> >>> +++ cfe/trunk/test/Sema/tautological-constant-compare.c Fri Dec 8 >> >>> 08:54:08 2017 >> >>> @@ -94,17 +94,15 @@ int main() >> >>> if (-32768 >= s) >> >>> return 0; >> >>> - // Note: both sides are promoted to unsigned long prior to the >> >>> comparison, so >> >>> - // it is perfectly possible for a short to compare greater than >> >>> 32767UL. >> >>> if (s == 32767UL) >> >>> return 0; >> >>> if (s != 32767UL) >> >>> return 0; >> >>> if (s < 32767UL) >> >>> return 0; >> >>> - if (s <= 32767UL) >> >>> + if (s <= 32767UL) // expected-warning {{comparison 'short' <= >> 32767 is >> >>> always true}} >> >>> return 0; >> >>> - if (s > 32767UL) >> >>> + if (s > 32767UL) // expected-warning {{comparison 'short' > 32767 >> is >> >>> always false}} >> >>> return 0; >> >>> if (s >= 32767UL) >> >>> return 0; >> >>> @@ -113,66 +111,13 @@ int main() >> >>> return 0; >> >>> if (32767UL != s) >> >>> return 0; >> >>> - if (32767UL < s) >> >>> + if (32767UL < s) // expected-warning {{comparison 32767 < 'short' >> is >> >>> always false}} >> >>> return 0; >> >>> if (32767UL <= s) >> >>> return 0; >> >>> if (32767UL > s) >> >>> return 0; >> >>> - if (32767UL >= s) >> >>> - return 0; >> >>> - >> >>> - if (s == 0UL) >> >>> - return 0; >> >>> - if (s != 0UL) >> >>> - return 0; >> >>> - if (s < 0UL) // expected-warning {{comparison of unsigned >> expression < >> >>> 0 is always false}} >> >>> - return 0; >> >>> - if (s <= 0UL) >> >>> - return 0; >> >>> - if (s > 0UL) >> >>> - return 0; >> >>> - if (s >= 0UL) // expected-warning {{comparison of unsigned >> expression >> >>> >= 0 is always true}} >> >>> - return 0; >> >>> - >> >>> - if (0UL == s) >> >>> - return 0; >> >>> - if (0UL != s) >> >>> - return 0; >> >>> - if (0UL < s) >> >>> - return 0; >> >>> - if (0UL <= s) // expected-warning {{comparison of 0 <= unsigned >> >>> expression is always true}} >> >>> - return 0; >> >>> - if (0UL > s) // expected-warning {{comparison of 0 > unsigned >> >>> expression is always false}} >> >>> - return 0; >> >>> - if (0UL >= s) >> >>> - return 0; >> >>> - >> >>> - enum { ULONG_MAX = (2UL * (unsigned long)__LONG_MAX__ + 1UL) }; >> >>> - if (s == 2UL * (unsigned long)__LONG_MAX__ + 1UL) >> >>> - return 0; >> >>> - if (s != 2UL * (unsigned long)__LONG_MAX__ + 1UL) >> >>> - return 0; >> >>> - if (s < 2UL * (unsigned long)__LONG_MAX__ + 1UL) >> >>> - return 0; >> >>> - if (s <= 2UL * (unsigned long)__LONG_MAX__ + 1UL) // >> >>> expected-warning-re {{comparison 'short' <= {{.*}} is always true}} >> >>> - return 0; >> >>> - if (s > 2UL * (unsigned long)__LONG_MAX__ + 1UL) // >> >>> expected-warning-re {{comparison 'short' > {{.*}} is always false}} >> >>> - return 0; >> >>> - if (s >= 2UL * (unsigned long)__LONG_MAX__ + 1UL) >> >>> - return 0; >> >>> - >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL == s) >> >>> - return 0; >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL != s) >> >>> - return 0; >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL < s) // >> >>> expected-warning-re {{comparison {{.*}} < 'short' is always false}} >> >>> - return 0; >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL <= s) >> >>> - return 0; >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL > s) >> >>> - return 0; >> >>> - if (2UL * (unsigned long)__LONG_MAX__ + 1UL >= s) // >> >>> expected-warning-re {{comparison {{.*}} >= 'short' is always true}} >> >>> + if (32767UL >= s) // expected-warning {{comparison 32767 >= >> 'short' is >> >>> always true}} >> >>> return 0; >> >>> // FIXME: assumes two's complement >> >>> @@ -336,6 +281,8 @@ int main() >> >>> if (0 >= s) >> >>> return 0; >> >>> + // However the comparison with 0U would warn >> >>> + >> >>> unsigned short us = value(); >> >>> #ifdef TEST >> >>> >> >>> Modified: cfe/trunk/test/Sema/tautological-constant-enum-compare.c >> >>> URL: >> >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/taut >> ological-constant-enum-compare.c?rev=320162&r1=320161&r2=320162&view=diff >> >>> >> >>> ============================================================ >> ================== >> >>> --- cfe/trunk/test/Sema/tautological-constant-enum-compare.c >> (original) >> >>> +++ cfe/trunk/test/Sema/tautological-constant-enum-compare.c Fri >> Dec 8 >> >>> 08:54:08 2017 >> >>> @@ -9,96 +9,78 @@ int main() { >> >>> #ifdef SILENCE >> >>> // expected-no-diagnostics >> >>> -#else >> >>> - // If we promote to unsigned, it doesn't matter whether the enum's >> >>> underlying >> >>> - // type was signed. >> >>> - if (a < 0U) // expected-warning {{comparison of unsigned enum >> >>> expression < 0 is always false}} >> >>> - return 0; >> >>> - if (0U >= a) >> >>> - return 0; >> >>> - if (a > 0U) >> >>> - return 0; >> >>> - if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum >> >>> expression is always true}} >> >>> - return 0; >> >>> - if (a <= 0U) >> >>> - return 0; >> >>> - if (0U > a) // expected-warning {{comparison of 0 > unsigned enum >> >>> expression is always false}} >> >>> - return 0; >> >>> - if (a >= 0U) // expected-warning {{comparison of unsigned enum >> >>> expression >= 0 is always true}} >> >>> - return 0; >> >>> - if (0U < a) >> >>> - return 0; >> >>> +#endif >> >>> - if (a < 4294967295U) >> >>> +#ifdef UNSIGNED >> >>> +#ifndef SILENCE >> >>> + if (a < 0) // expected-warning {{comparison of unsigned enum >> >>> expression < 0 is always false}} >> >>> return 0; >> >>> - if (4294967295U >= a) // expected-warning {{comparison 4294967295 >> >= >> >>> 'enum A' is always true}} >> >>> + if (0 >= a) >> >>> return 0; >> >>> - if (a > 4294967295U) // expected-warning {{comparison 'enum A' > >> >>> 4294967295 is always false}} >> >>> + if (a > 0) >> >>> return 0; >> >>> - if (4294967295U <= a) >> >>> + if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum >> >>> expression is always true}} >> >>> return 0; >> >>> - if (a <= 4294967295U) // expected-warning {{comparison 'enum A' <= >> >>> 4294967295 is always true}} >> >>> + if (a <= 0) >> >>> return 0; >> >>> - if (4294967295U > a) >> >>> + if (0 > a) // expected-warning {{comparison of 0 > unsigned enum >> >>> expression is always false}} >> >>> return 0; >> >>> - if (a >= 4294967295U) >> >>> + if (a >= 0) // expected-warning {{comparison of unsigned enum >> >>> expression >= 0 is always true}} >> >>> return 0; >> >>> - if (4294967295U < a) // expected-warning {{comparison 4294967295 < >> >>> 'enum A' is always false}} >> >>> + if (0 < a) >> >>> return 0; >> >>> - if (a < 2147483647U) >> >>> + if (a < 0U) // expected-warning {{comparison of unsigned enum >> >>> expression < 0 is always false}} >> >>> return 0; >> >>> - if (2147483647U >= a) >> >>> + if (0U >= a) >> >>> return 0; >> >>> - if (a > 2147483647U) >> >>> + if (a > 0U) >> >>> return 0; >> >>> - if (2147483647U <= a) >> >>> + if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum >> >>> expression is always true}} >> >>> return 0; >> >>> - if (a <= 2147483647U) >> >>> + if (a <= 0U) >> >>> return 0; >> >>> - if (2147483647U > a) >> >>> + if (0U > a) // expected-warning {{comparison of 0 > unsigned enum >> >>> expression is always false}} >> >>> return 0; >> >>> - if (a >= 2147483647U) >> >>> + if (a >= 0U) // expected-warning {{comparison of unsigned enum >> >>> expression >= 0 is always true}} >> >>> return 0; >> >>> - if (2147483647U < a) >> >>> + if (0U < a) >> >>> return 0; >> >>> -#endif >> >>> -#if defined(UNSIGNED) && !defined(SILENCE) >> >>> - if (a < 0) // expected-warning {{comparison of unsigned enum >> >>> expression < 0 is always false}} >> >>> + if (a < 4294967295) >> >>> return 0; >> >>> - if (0 >= a) >> >>> + if (4294967295 >= a) // expected-warning {{comparison 4294967295 >= >> >>> 'enum A' is always true}} >> >>> return 0; >> >>> - if (a > 0) >> >>> + if (a > 4294967295) // expected-warning {{comparison 'enum A' > >> >>> 4294967295 is always false}} >> >>> return 0; >> >>> - if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum >> >>> expression is always true}} >> >>> + if (4294967295 <= a) >> >>> return 0; >> >>> - if (a <= 0) >> >>> + if (a <= 4294967295) // expected-warning {{comparison 'enum A' <= >> >>> 4294967295 is always true}} >> >>> return 0; >> >>> - if (0 > a) // expected-warning {{comparison of 0 > unsigned enum >> >>> expression is always false}} >> >>> + if (4294967295 > a) >> >>> return 0; >> >>> - if (a >= 0) // expected-warning {{comparison of unsigned enum >> >>> expression >= 0 is always true}} >> >>> + if (a >= 4294967295) >> >>> return 0; >> >>> - if (0 < a) >> >>> + if (4294967295 < a) // expected-warning {{comparison 4294967295 < >> >>> 'enum A' is always false}} >> >>> return 0; >> >>> - if (a < 4294967295) >> >>> + if (a < 4294967295U) >> >>> return 0; >> >>> - if (4294967295 >= a) // expected-warning {{comparison 4294967295 >= >> >>> 'enum A' is always true}} >> >>> + if (4294967295U >= a) // expected-warning {{comparison 4294967295 >> >= >> >>> 'enum A' is always true}} >> >>> return 0; >> >>> - if (a > 4294967295) // expected-warning {{comparison 'enum A' > >> >>> 4294967295 is always false}} >> >>> + if (a > 4294967295U) // expected-warning {{comparison 'enum A' > >> >>> 4294967295 is always false}} >> >>> return 0; >> >>> - if (4294967295 <= a) >> >>> + if (4294967295U <= a) >> >>> return 0; >> >>> - if (a <= 4294967295) // expected-warning {{comparison 'enum A' <= >> >>> 4294967295 is always true}} >> >>> + if (a <= 4294967295U) // expected-warning {{comparison 'enum A' <= >> >>> 4294967295 is always true}} >> >>> return 0; >> >>> - if (4294967295 > a) >> >>> + if (4294967295U > a) >> >>> return 0; >> >>> - if (a >= 4294967295) >> >>> + if (a >= 4294967295U) >> >>> return 0; >> >>> - if (4294967295 < a) // expected-warning {{comparison 4294967295 < >> >>> 'enum A' is always false}} >> >>> + if (4294967295U < a) // expected-warning {{comparison 4294967295 < >> >>> 'enum A' is always false}} >> >>> return 0; >> >>> -#else // SIGNED || SILENCE >> >>> +#else // SILENCE >> >>> if (a < 0) >> >>> return 0; >> >>> if (0 >= a) >> >>> @@ -116,24 +98,23 @@ int main() { >> >>> if (0 < a) >> >>> return 0; >> >>> -#ifndef SILENCE >> >>> - if (a < 4294967295) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always true}} >> >>> + if (a < 0U) >> >>> return 0; >> >>> - if (4294967295 >= a) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always true}} >> >>> + if (0U >= a) >> >>> return 0; >> >>> - if (a > 4294967295) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always false}} >> >>> + if (a > 0U) >> >>> return 0; >> >>> - if (4294967295 <= a) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always false}} >> >>> + if (0U <= a) >> >>> return 0; >> >>> - if (a <= 4294967295) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always true}} >> >>> + if (a <= 0U) >> >>> return 0; >> >>> - if (4294967295 > a) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always true}} >> >>> + if (0U > a) >> >>> return 0; >> >>> - if (a >= 4294967295) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always false}} >> >>> + if (a >= 0U) >> >>> return 0; >> >>> - if (4294967295 < a) // expected-warning {{comparison of constant >> >>> 4294967295 with expression of type 'enum A' is always false}} >> >>> + if (0U < a) >> >>> return 0; >> >>> -#else >> >>> + >> >>> if (a < 4294967295) >> >>> return 0; >> >>> if (4294967295 >= a) >> >>> @@ -150,10 +131,26 @@ int main() { >> >>> return 0; >> >>> if (4294967295 < a) >> >>> return 0; >> >>> -#endif >> >>> -#endif >> >>> -#if defined(SIGNED) && !defined(SILENCE) >> >>> + if (a < 4294967295U) >> >>> + return 0; >> >>> + if (4294967295U >= a) >> >>> + return 0; >> >>> + if (a > 4294967295U) >> >>> + return 0; >> >>> + if (4294967295U <= a) >> >>> + return 0; >> >>> + if (a <= 4294967295U) >> >>> + return 0; >> >>> + if (4294967295U > a) >> >>> + return 0; >> >>> + if (a >= 4294967295U) >> >>> + return 0; >> >>> + if (4294967295U < a) >> >>> + return 0; >> >>> +#endif >> >>> +#elif defined(SIGNED) >> >>> +#ifndef SILENCE >> >>> if (a < -2147483648 <(214)%20748-3648>) // expected-warning >> {{comparison 'enum A' < >> >>> -2147483648 <(214)%20748-3648> is always false}} >> >>> return 0; >> >>> if (-2147483648 <(214)%20748-3648> >= a) >> >>> @@ -187,25 +184,24 @@ int main() { >> >>> return 0; >> >>> if (2147483647 <(214)%20748-3647> < a) // expected-warning >> {{comparison 2147483647 <(214)%20748-3647> < >> >>> 'enum A' is always false}} >> >>> return 0; >> >>> -#elif defined(UNSIGNED) && !defined(SILENCE) >> >>> -#ifndef SILENCE >> >>> - if (a < -2147483648 <(214)%20748-3648>) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always false}} >> >>> + >> >>> + if (a < 2147483647U) >> >>> return 0; >> >>> - if (-2147483648 <(214)%20748-3648> >= a) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always false}} >> >>> + if (2147483647U >= a) // expected-warning {{comparison 2147483647 >> <(214)%20748-3647> >= >> >>> 'enum A' is always true}} >> >>> return 0; >> >>> - if (a > -2147483648 <(214)%20748-3648>) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always true}} >> >>> + if (a > 2147483647U) // expected-warning {{comparison 'enum A' > >> >>> 2147483647 <(214)%20748-3647> is always false}} >> >>> return 0; >> >>> - if (-2147483648 <(214)%20748-3648> <= a) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always true}} >> >>> + if (2147483647U <= a) >> >>> return 0; >> >>> - if (a <= -2147483648 <(214)%20748-3648>) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always false}} >> >>> + if (a <= 2147483647U) // expected-warning {{comparison 'enum A' <= >> >>> 2147483647 <(214)%20748-3647> is always true}} >> >>> return 0; >> >>> - if (-2147483648 <(214)%20748-3648> > a) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always false}} >> >>> + if (2147483647U > a) >> >>> return 0; >> >>> - if (a >= -2147483648 <(214)%20748-3648>) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always true}} >> >>> + if (a >= 2147483647U) >> >>> return 0; >> >>> - if (-2147483648 <(214)%20748-3648> < a) // expected-warning >> {{comparison of constant >> >>> -2147483648 <(214)%20748-3648> with expression of type 'enum A' is >> always true}} >> >>> + if (2147483647U < a) // expected-warning {{comparison 2147483647 >> <(214)%20748-3647> < >> >>> 'enum A' is always false}} >> >>> return 0; >> >>> -#else >> >>> +#else // SILENCE >> >>> if (a < -2147483648 <(214)%20748-3648>) >> >>> return 0; >> >>> if (-2147483648 <(214)%20748-3648> >= a) >> >>> @@ -222,7 +218,6 @@ int main() { >> >>> return 0; >> >>> if (-2147483648 <(214)%20748-3648> < a) >> >>> return 0; >> >>> -#endif >> >>> if (a < 2147483647 <(214)%20748-3647>) >> >>> return 0; >> >>> @@ -240,6 +235,24 @@ int main() { >> >>> return 0; >> >>> if (2147483647 <(214)%20748-3647> < a) >> >>> return 0; >> >>> + >> >>> + if (a < 2147483647U) >> >>> + return 0; >> >>> + if (2147483647U >= a) >> >>> + return 0; >> >>> + if (a > 2147483647U) >> >>> + return 0; >> >>> + if (2147483647U <= a) >> >>> + return 0; >> >>> + if (a <= 2147483647U) >> >>> + return 0; >> >>> + if (2147483647U > a) >> >>> + return 0; >> >>> + if (a >= 2147483647U) >> >>> + return 0; >> >>> + if (2147483647U < a) >> >>> + return 0; >> >>> +#endif >> >>> #endif >> >>> return 1; >> >>> >> >>> Modified: cfe/trunk/test/SemaCXX/compare.cpp >> >>> URL: >> >>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ >> compare.cpp?rev=320162&r1=320161&r2=320162&view=diff >> >>> >> >>> ============================================================ >> ================== >> >>> --- cfe/trunk/test/SemaCXX/compare.cpp (original) >> >>> +++ cfe/trunk/test/SemaCXX/compare.cpp Fri Dec 8 08:54:08 2017 >> >>> @@ -245,8 +245,8 @@ void test4(short s) { >> >>> // unsigned. >> >>> const unsigned B = -1; >> >>> void (s < B); // expected-warning{{comparison of integers of >> >>> different signs: 'short' and 'const unsigned int'}} >> >>> - void (s > B); // expected-warning{{comparison 'short' > 4294967295 >> is >> >>> always false}} >> >>> - void (s <= B); // expected-warning{{comparison 'short' <= >> 4294967295 >> >>> is always true}} >> >>> + void (s > B); // expected-warning{{comparison of integers of >> different >> >>> signs: 'short' and 'const unsigned int'}} >> >>> + void (s <= B); // expected-warning{{comparison of integers of >> >>> different signs: 'short' and 'const unsigned int'}} >> >>> void (s >= B); // expected-warning{{comparison of integers of >> >>> different signs: 'short' and 'const unsigned int'}} >> >>> void (s == B); // expected-warning{{comparison of integers of >> >>> different signs: 'short' and 'const unsigned int'}} >> >>> void (s != B); // expected-warning{{comparison of integers of >> >>> different signs: 'short' and 'const unsigned int'}} >> >>> >> >>> >> >>> _______________________________________________ >> >>> cfe-commits mailing list >> >>> cfe-commits@lists.llvm.org >> >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >>> >> >> >> >> >> >> -- >> >> >> >> -Bill Seurer >> >> >> >> >> >> _______________________________________________ >> >> cfe-commits mailing list >> >> cfe-commits@lists.llvm.org >> >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> > >> > >> > >> > _______________________________________________ >> > cfe-commits mailing list >> > cfe-commits@lists.llvm.org >> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> > >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> > >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits