Changeset View
Changeset View
Standalone View
Standalone View
lib/Sema/SemaChecking.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 8,153 Lines • ▼ Show 20 Lines | struct IntRange { | ||||
/// True if the int is known not to have negative values. | /// True if the int is known not to have negative values. | ||||
bool NonNegative; | bool NonNegative; | ||||
IntRange(unsigned Width, bool NonNegative) | IntRange(unsigned Width, bool NonNegative) | ||||
: Width(Width), NonNegative(NonNegative) | : Width(Width), NonNegative(NonNegative) | ||||
{} | {} | ||||
/// Indicate whether the specified integer ranges are identical. | |||||
friend bool operator==(const IntRange &LHS, const IntRange &RHS) { | |||||
return LHS.Width == RHS.Width && LHS.NonNegative == RHS.NonNegative; | |||||
} | |||||
/// Returns the range of the bool type. | /// Returns the range of the bool type. | ||||
static IntRange forBoolType() { | static IntRange forBoolType() { | ||||
return IntRange(1, true); | return IntRange(1, true); | ||||
} | } | ||||
/// Returns the range of an opaque value of the given integral type. | /// Returns the range of an opaque value of the given integral type. | ||||
static IntRange forValueOfType(ASTContext &C, QualType T) { | static IntRange forValueOfType(ASTContext &C, QualType T) { | ||||
return forValueOfCanonicalType(C, | return forValueOfCanonicalType(C, | ||||
▲ Show 20 Lines • Show All 413 Lines • ▼ Show 20 Lines | bool isNonBooleanUnsignedValue(Expr *E) { | ||||
// is an integer type; and is either unsigned after implicit casts, | // is an integer type; and is either unsigned after implicit casts, | ||||
// or was unsigned before implicit casts. | // or was unsigned before implicit casts. | ||||
return isNonBooleanIntegerValue(E) && | return isNonBooleanIntegerValue(E) && | ||||
(!E->getType()->isSignedIntegerType() || | (!E->getType()->isSignedIntegerType() || | ||||
!E->IgnoreParenImpCasts()->getType()->isSignedIntegerType()); | !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType()); | ||||
} | } | ||||
enum class LimitType { | enum class LimitType { | ||||
None = 0, // Just a zero-initalizer | |||||
Max = 1U << 0U, // e.g. 32767 for short | Max = 1U << 0U, // e.g. 32767 for short | ||||
Min = 1U << 1U, // e.g. -32768 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 | 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 }; | // same time; e.g. in C++, A::a in enum A { a = 0 }; | ||||
DataModelDependent = 1U << 2U, // is this limit is always the limit, or only | |||||
// for the current data model | |||||
}; | }; | ||||
/// LimitType is a bitset, thus a few helpers are needed | |||||
LimitType operator|(LimitType LHS, LimitType RHS) { | |||||
return static_cast<LimitType>( | |||||
static_cast<std::underlying_type<LimitType>::type>(LHS) | | |||||
static_cast<std::underlying_type<LimitType>::type>(RHS)); | |||||
} | |||||
LimitType operator&(LimitType LHS, LimitType RHS) { | |||||
return static_cast<LimitType>( | |||||
static_cast<std::underlying_type<LimitType>::type>(LHS) & | |||||
static_cast<std::underlying_type<LimitType>::type>(RHS)); | |||||
} | |||||
bool IsSet(llvm::Optional<LimitType> LHS, LimitType RHS) { | |||||
return LHS && ((*LHS) & RHS) == RHS; | |||||
} | |||||
bool HasEnumType(Expr *E) { | |||||
// Strip off implicit integral promotions. | |||||
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { | |||||
if (ICE->getCastKind() != CK_IntegralCast && | |||||
ICE->getCastKind() != CK_NoOp) | |||||
break; | |||||
E = ICE->getSubExpr(); | |||||
} | |||||
return E->getType()->isEnumeralType(); | |||||
} | |||||
/// Checks whether Expr 'Constant' may be the | /// Checks whether Expr 'Constant' may be the | ||||
/// std::numeric_limits<>::max() or std::numeric_limits<>::min() | /// std::numeric_limits<>::max() or std::numeric_limits<>::min() | ||||
/// of the Expr 'Other'. If true, then returns the limit type (min or max). | /// of the Expr 'Other'. If true, then returns the limit type (min or max). | ||||
/// The Value is the evaluation of Constant | /// The Value is the evaluation of Constant | ||||
llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other, | llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other, | ||||
const llvm::APSInt &Value) { | const llvm::APSInt &Value) { | ||||
if (IsEnumConstOrFromMacro(S, Constant)) | if (IsEnumConstOrFromMacro(S, Constant)) | ||||
return llvm::Optional<LimitType>(); | return llvm::Optional<LimitType>(); | ||||
if (isNonBooleanUnsignedValue(Other) && Value == 0) | if (isNonBooleanUnsignedValue(Other) && Value == 0) | ||||
return LimitType::Min; | return LimitType::Min; | ||||
// TODO: Investigate using GetExprRange() to get tighter bounds | // TODO: Investigate using GetExprRange() to get tighter bounds | ||||
// on the bit ranges. | // on the bit ranges. | ||||
QualType ConstT = Constant->IgnoreParenImpCasts()->getType(); | |||||
QualType OtherT = Other->IgnoreParenImpCasts()->getType(); | QualType OtherT = Other->IgnoreParenImpCasts()->getType(); | ||||
if (const auto *AT = OtherT->getAs<AtomicType>()) | IntRange ConstRange = IntRange::forValueOfType(S.Context, ConstT); | ||||
OtherT = AT->getValueType(); | |||||
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); | IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); | ||||
// Special-case for C++ for enum with one enumerator with value of 0. | // Special-case for C++ for enum with one enumerator with value of 0. | ||||
if (OtherRange.Width == 0) | if (OtherRange.Width == 0) | ||||
return Value == 0 ? LimitType::Both : llvm::Optional<LimitType>(); | return Value == 0 ? LimitType::Both : llvm::Optional<LimitType>(); | ||||
LimitType LT = LimitType::None; | |||||
if(ConstRange == OtherRange && ConstT != OtherT && !HasEnumType(Other)) | |||||
LT = LimitType::DataModelDependent; | |||||
if (llvm::APSInt::isSameValue( | if (llvm::APSInt::isSameValue( | ||||
llvm::APSInt::getMaxValue(OtherRange.Width, | llvm::APSInt::getMaxValue(OtherRange.Width, | ||||
OtherT->isUnsignedIntegerType()), | OtherT->isUnsignedIntegerType()), | ||||
Value)) | Value)) | ||||
return LimitType::Max; | return LimitType::Max | LT; | ||||
if (llvm::APSInt::isSameValue( | if (llvm::APSInt::isSameValue( | ||||
llvm::APSInt::getMinValue(OtherRange.Width, | llvm::APSInt::getMinValue(OtherRange.Width, | ||||
OtherT->isUnsignedIntegerType()), | OtherT->isUnsignedIntegerType()), | ||||
Value)) | Value)) | ||||
return LimitType::Min; | return LimitType::Min | LT; | ||||
return llvm::None; | return llvm::None; | ||||
} | } | ||||
bool HasEnumType(Expr *E) { | |||||
// Strip off implicit integral promotions. | |||||
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { | |||||
if (ICE->getCastKind() != CK_IntegralCast && | |||||
ICE->getCastKind() != CK_NoOp) | |||||
break; | |||||
E = ICE->getSubExpr(); | |||||
} | |||||
return E->getType()->isEnumeralType(); | |||||
} | |||||
bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant, | bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant, | ||||
Expr *Other, const llvm::APSInt &Value, | Expr *Other, const llvm::APSInt &Value, | ||||
bool RhsConstant) { | bool RhsConstant) { | ||||
// Disable warning in template instantiations | // Disable warning in template instantiations | ||||
// and only analyze <, >, <= and >= operations. | // and only analyze <, >, <= and >= operations. | ||||
if (S.inTemplateInstantiation() || !E->isRelationalOp()) | if (S.inTemplateInstantiation() || !E->isRelationalOp()) | ||||
return false; | return false; | ||||
BinaryOperatorKind Op = E->getOpcode(); | BinaryOperatorKind Op = E->getOpcode(); | ||||
QualType OType = Other->IgnoreParenImpCasts()->getType(); | QualType OType = Other->IgnoreParenImpCasts()->getType(); | ||||
llvm::Optional<LimitType> ValueType; // Which limit (min/max) is the constant? | llvm::Optional<LimitType> ValueType; // Which limit (min/max) is the constant? | ||||
if (!(isNonBooleanIntegerValue(Other) && | if (!(isNonBooleanIntegerValue(Other) && | ||||
(ValueType = IsTypeLimit(S, Constant, Other, Value)))) | (ValueType = IsTypeLimit(S, Constant, Other, Value)))) | ||||
return false; | return false; | ||||
bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant; | bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant; | ||||
bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE); | bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE); | ||||
if (ValueType != LimitType::Both) { | if (!IsSet(ValueType, LimitType::Both)) { | ||||
bool ResultWhenConstNeOther = | bool ResultWhenConstNeOther = | ||||
ConstIsLowerBound ^ (ValueType == LimitType::Max); | ConstIsLowerBound ^ IsSet(ValueType, LimitType::Max); | ||||
if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) | if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) | ||||
return false; // The comparison is not tautological. | return false; // The comparison is not tautological. | ||||
} else if (ResultWhenConstEqualsOther == ConstIsLowerBound) | } else if (ResultWhenConstEqualsOther == ConstIsLowerBound) | ||||
return false; // The comparison is not tautological. | return false; // The comparison is not tautological. | ||||
const bool Result = ResultWhenConstEqualsOther; | const bool Result = ResultWhenConstEqualsOther; | ||||
unsigned Diag = (isNonBooleanUnsignedValue(Other) && Value == 0) | unsigned Diag = (isNonBooleanUnsignedValue(Other) && Value == 0) | ||||
? (HasEnumType(Other) | ? (HasEnumType(Other) | ||||
? diag::warn_unsigned_enum_always_true_comparison | ? diag::warn_unsigned_enum_always_true_comparison | ||||
: diag::warn_unsigned_always_true_comparison) | : diag::warn_unsigned_always_true_comparison) | ||||
: IsSet(ValueType, LimitType::DataModelDependent) | |||||
? diag::warn_maybe_tautological_constant_compare | |||||
: diag::warn_tautological_constant_compare; | : diag::warn_tautological_constant_compare; | ||||
// Should be enough for uint128 (39 decimal digits) | // Should be enough for uint128 (39 decimal digits) | ||||
SmallString<64> PrettySourceValue; | SmallString<64> PrettySourceValue; | ||||
llvm::raw_svector_ostream OS(PrettySourceValue); | llvm::raw_svector_ostream OS(PrettySourceValue); | ||||
OS << Value; | OS << Value; | ||||
S.Diag(E->getOperatorLoc(), Diag) | S.Diag(E->getOperatorLoc(), Diag) | ||||
<< RhsConstant << OType << E->getOpcodeStr() << OS.str() << Result | << RhsConstant << OType << E->getOpcodeStr() << OS.str() << Result | ||||
▲ Show 20 Lines • Show All 3,762 Lines • Show Last 20 Lines |