Factor out comparison handling for arithmetic types.

This is not quite NFC: we don't perform the usual arithmetic conversions unless
we have an operand of arithmetic or enumeration type any more. This matches the
standard rule, but actually has no effect other than to marginally improve our
diagnostics for the non-arithmetic, non-enumeration cases (by not performing
integral promotions on one operand if the other is a pointer).

llvm-svn: 322024
This commit is contained in:
Richard Smith 2018-01-08 21:12:04 +00:00
parent 215284d089
commit a12bf9106a
3 changed files with 55 additions and 37 deletions

View File

@ -10405,7 +10405,10 @@ private:
const AttrVec *Attrs = nullptr,
const FunctionDecl *FD = nullptr);
void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
public:
void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS);
private:
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
void CheckBoolLikeConversion(Expr *E, SourceLocation CC);
void CheckForIntOverflow(Expr *E);

View File

@ -9598,7 +9598,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
Expr *RHSStripped = RHS->IgnoreParenImpCasts();
QualType LHSType = LHS->getType();
QualType RHSType = RHS->getType();
if (LHSType->hasFloatingRepresentation() ||
(LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) ||
LHS->getLocStart().isMacroID() || RHS->getLocStart().isMacroID() ||
@ -9636,9 +9635,8 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
S.PDiag(diag::warn_comparison_always)
<< 0 /*self-comparison*/ << !Result.empty()
<< Result);
} else if (DL && DR && LHSType->isArrayType() && RHSType->isArrayType() &&
!DL->getType()->isReferenceType() &&
!DR->getType()->isReferenceType() &&
} else if (DL && DR &&
DL->getType()->isArrayType() && DR->getType()->isArrayType() &&
!DL->isWeak() && !DR->isWeak()) {
// What is it always going to evaluate to?
StringRef Result;
@ -9689,10 +9687,53 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
}
}
static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
// C99 6.5.8p3 / C99 6.5.9p4
QualType Type = S.UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
assert(Type->isArithmeticType() || Type->isEnumeralType());
checkEnumComparison(S, Loc, LHS.get(), RHS.get());
enum { StrongEquality, PartialOrdering, StrongOrdering } Ordering;
if (Type->isAnyComplexType())
Ordering = StrongEquality;
else if (Type->isFloatingType())
Ordering = PartialOrdering;
else
Ordering = StrongOrdering;
if (Ordering == StrongEquality && BinaryOperator::isRelationalOp(Opc))
return S.InvalidOperands(Loc, LHS, RHS);
// Check for comparisons of floating point operands using != and ==.
if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc))
S.CheckFloatComparison(Loc, LHS.get(), RHS.get());
// The result of comparisons is 'bool' in C++, 'int' in C.
// FIXME: For BO_Cmp, return the relevant comparison category type.
return S.Context.getLogicalOperationType();
}
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, BinaryOperatorKind Opc,
bool IsRelational) {
// Comparisons expect an rvalue, so convert to rvalue before any
// type-related checks.
LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
if (LHS.isInvalid())
return QualType();
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
if (RHS.isInvalid())
return QualType();
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
// Handle vector comparisons separately.
@ -9700,36 +9741,17 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
RHS.get()->getType()->isVectorType())
return CheckVectorCompareOperands(LHS, RHS, Loc, Opc);
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
// C99 6.5.8p3 / C99 6.5.9p4
UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
if ((LHSType->isArithmeticType() || LHSType->isEnumeralType()) &&
(RHSType->isArithmeticType() || RHSType->isEnumeralType()))
return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc);
LHSType = LHS.get()->getType();
RHSType = RHS.get()->getType();
// The result of comparisons is 'bool' in C++, 'int' in C.
QualType ResultTy = Context.getLogicalOperationType();
if (IsRelational) {
if (LHSType->isRealType() && RHSType->isRealType())
return ResultTy;
} else {
// Check for comparisons of floating point operands using != and ==.
if (LHSType->hasFloatingRepresentation())
CheckFloatComparison(Loc, LHS.get(), RHS.get());
if (LHSType->isArithmeticType() && RHSType->isArithmeticType())
return ResultTy;
}
const Expr::NullPointerConstantKind LHSNullKind =
LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
const Expr::NullPointerConstantKind RHSNullKind =
@ -9903,13 +9925,6 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
else
return ResultTy;
}
// Handle scoped enumeration types specifically, since they don't promote
// to integers.
if (LHS.get()->getType()->isEnumeralType() &&
Context.hasSameUnqualifiedType(LHS.get()->getType(),
RHS.get()->getType()))
return ResultTy;
}
// Handle block pointer types.

View File

@ -12,6 +12,6 @@ void test() {
if (cp < fp) {} // expected-warning {{comparison of distinct pointer types ('char *' and 'struct foo *')}}
if (fp < bp) {} // expected-warning {{comparison of distinct pointer types ('struct foo *' and 'struct bar *')}}
if (ip < 7) {} // expected-warning {{comparison between pointer and integer ('int *' and 'int')}}
if (sint < ip) {} // expected-warning {{comparison between pointer and integer ('int' and 'int *')}}
if (sint < ip) {} // expected-warning {{comparison between pointer and integer ('short' and 'int *')}}
if (ip == cp) {} // expected-warning {{comparison of distinct pointer types ('int *' and 'char *')}}
}