forked from OSchip/llvm-project
Factor out common tautological comparison code from scalar and vector compare checking.
In passing, improve vector compare diagnostic to match scalar compare diagnostic. llvm-svn: 321972
This commit is contained in:
parent
e9f44e1b80
commit
abbb8ada45
|
@ -7906,7 +7906,7 @@ def note_ref_subobject_of_member_declared_here : Note<
|
|||
// should result in a warning, since these always evaluate to a constant.
|
||||
// Array comparisons have similar warnings
|
||||
def warn_comparison_always : Warning<
|
||||
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">,
|
||||
"%select{self-|array }0comparison always evaluates to %select{a constant|%2}1">,
|
||||
InGroup<TautologicalCompare>;
|
||||
def warn_comparison_bitwise_always : Warning<
|
||||
"bitwise comparison always evaluates to %select{false|true}0">,
|
||||
|
|
|
@ -9580,7 +9580,8 @@ public:
|
|||
bool AllowBothBool, bool AllowBoolConversion);
|
||||
QualType GetSignedVectorType(QualType V);
|
||||
QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc, bool isRelational);
|
||||
SourceLocation Loc,
|
||||
BinaryOperatorKind Opc);
|
||||
QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc);
|
||||
|
||||
|
|
|
@ -9600,31 +9600,21 @@ static ValueDecl *getCompareDecl(Expr *E) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// C99 6.5.8, C++ [expr.rel]
|
||||
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc, BinaryOperatorKind Opc,
|
||||
bool IsRelational) {
|
||||
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
|
||||
/// Diagnose some forms of syntactically-obvious tautological comparison.
|
||||
static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
|
||||
Expr *LHS, Expr *RHS,
|
||||
BinaryOperatorKind Opc) {
|
||||
Expr *LHSStripped = LHS->IgnoreParenImpCasts();
|
||||
Expr *RHSStripped = RHS->IgnoreParenImpCasts();
|
||||
|
||||
// Handle vector comparisons separately.
|
||||
if (LHS.get()->getType()->isVectorType() ||
|
||||
RHS.get()->getType()->isVectorType())
|
||||
return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational);
|
||||
QualType LHSType = LHS->getType();
|
||||
QualType RHSType = RHS->getType();
|
||||
if (LHSType->hasFloatingRepresentation() ||
|
||||
(LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) ||
|
||||
LHS->getLocStart().isMacroID() || RHS->getLocStart().isMacroID() ||
|
||||
S.inTemplateInstantiation())
|
||||
return;
|
||||
|
||||
QualType LHSType = LHS.get()->getType();
|
||||
QualType RHSType = RHS.get()->getType();
|
||||
|
||||
Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
|
||||
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
|
||||
|
||||
checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
|
||||
diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
|
||||
|
||||
if (!LHSType->hasFloatingRepresentation() &&
|
||||
!(LHSType->isBlockPointerType() && IsRelational) &&
|
||||
!LHS.get()->getLocStart().isMacroID() &&
|
||||
!RHS.get()->getLocStart().isMacroID() &&
|
||||
!inTemplateInstantiation()) {
|
||||
// For non-floating point types, check for self-comparisons of the form
|
||||
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
|
||||
// often indicate logic errors in the program.
|
||||
|
@ -9638,31 +9628,46 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
ValueDecl *DL = getCompareDecl(LHSStripped);
|
||||
ValueDecl *DR = getCompareDecl(RHSStripped);
|
||||
if (DL && DR && DL == DR && !IsWithinTemplateSpecialization(DL)) {
|
||||
DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
|
||||
<< 0 // self-
|
||||
<< (Opc == BO_EQ
|
||||
|| Opc == BO_LE
|
||||
|| Opc == BO_GE));
|
||||
StringRef Result;
|
||||
switch (Opc) {
|
||||
case BO_EQ: case BO_LE: case BO_GE:
|
||||
Result = "true";
|
||||
break;
|
||||
case BO_NE: case BO_LT: case BO_GT:
|
||||
Result = "false";
|
||||
break;
|
||||
case BO_Cmp:
|
||||
Result = "'std::strong_ordering::equal'";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
S.DiagRuntimeBehavior(Loc, nullptr,
|
||||
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()) {
|
||||
// what is it always going to eval to?
|
||||
char always_evals_to;
|
||||
// What is it always going to evaluate to?
|
||||
// FIXME: This is wrong if DL and DR are different Decls for the same
|
||||
// entity. It's also wrong if DL and/or DR are weak declarations.
|
||||
StringRef Result;
|
||||
switch(Opc) {
|
||||
case BO_EQ: // e.g. array1 == array2
|
||||
always_evals_to = 0; // false
|
||||
Result = "false";
|
||||
break;
|
||||
case BO_NE: // e.g. array1 != array2
|
||||
always_evals_to = 1; // true
|
||||
Result = "true";
|
||||
break;
|
||||
default:
|
||||
// best we can say is 'a constant'
|
||||
always_evals_to = 2; // e.g. array1 <= array2
|
||||
default: // e.g. array1 <= array2
|
||||
// The best we can say is 'a constant'
|
||||
break;
|
||||
}
|
||||
DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
|
||||
<< 1 // array
|
||||
<< always_evals_to);
|
||||
S.DiagRuntimeBehavior(Loc, nullptr,
|
||||
S.PDiag(diag::warn_comparison_always)
|
||||
<< 1 /*array comparison*/
|
||||
<< !Result.empty() << Result);
|
||||
}
|
||||
|
||||
if (isa<CastExpr>(LHSStripped))
|
||||
|
@ -9671,30 +9676,48 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
RHSStripped = RHSStripped->IgnoreParenCasts();
|
||||
|
||||
// Warn about comparisons against a string constant (unless the other
|
||||
// operand is null), the user probably wants strcmp.
|
||||
Expr *literalString = nullptr;
|
||||
Expr *literalStringStripped = nullptr;
|
||||
// operand is null); the user probably wants strcmp.
|
||||
Expr *LiteralString = nullptr;
|
||||
Expr *LiteralStringStripped = nullptr;
|
||||
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
|
||||
!RHSStripped->isNullPointerConstant(Context,
|
||||
!RHSStripped->isNullPointerConstant(S.Context,
|
||||
Expr::NPC_ValueDependentIsNull)) {
|
||||
literalString = LHS.get();
|
||||
literalStringStripped = LHSStripped;
|
||||
LiteralString = LHS;
|
||||
LiteralStringStripped = LHSStripped;
|
||||
} else if ((isa<StringLiteral>(RHSStripped) ||
|
||||
isa<ObjCEncodeExpr>(RHSStripped)) &&
|
||||
!LHSStripped->isNullPointerConstant(Context,
|
||||
!LHSStripped->isNullPointerConstant(S.Context,
|
||||
Expr::NPC_ValueDependentIsNull)) {
|
||||
literalString = RHS.get();
|
||||
literalStringStripped = RHSStripped;
|
||||
LiteralString = RHS;
|
||||
LiteralStringStripped = RHSStripped;
|
||||
}
|
||||
|
||||
if (literalString) {
|
||||
DiagRuntimeBehavior(Loc, nullptr,
|
||||
PDiag(diag::warn_stringcompare)
|
||||
<< isa<ObjCEncodeExpr>(literalStringStripped)
|
||||
<< literalString->getSourceRange());
|
||||
if (LiteralString) {
|
||||
S.DiagRuntimeBehavior(Loc, nullptr,
|
||||
S.PDiag(diag::warn_stringcompare)
|
||||
<< isa<ObjCEncodeExpr>(LiteralStringStripped)
|
||||
<< LiteralString->getSourceRange());
|
||||
}
|
||||
}
|
||||
|
||||
// C99 6.5.8, C++ [expr.rel]
|
||||
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc, BinaryOperatorKind Opc,
|
||||
bool IsRelational) {
|
||||
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
|
||||
|
||||
// Handle vector comparisons separately.
|
||||
if (LHS.get()->getType()->isVectorType() ||
|
||||
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())
|
||||
|
@ -10101,7 +10124,7 @@ QualType Sema::GetSignedVectorType(QualType V) {
|
|||
/// types.
|
||||
QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||||
SourceLocation Loc,
|
||||
bool IsRelational) {
|
||||
BinaryOperatorKind Opc) {
|
||||
// Check to make sure we're operating on vectors of the same type and width,
|
||||
// Allowing one side to be a scalar of element type.
|
||||
QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
|
||||
|
@ -10121,21 +10144,11 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
// For non-floating point types, check for self-comparisons of the form
|
||||
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
|
||||
// often indicate logic errors in the program.
|
||||
if (!LHSType->hasFloatingRepresentation() && !inTemplateInstantiation()) {
|
||||
if (DeclRefExpr* DRL
|
||||
= dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts()))
|
||||
if (DeclRefExpr* DRR
|
||||
= dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParenImpCasts()))
|
||||
if (DRL->getDecl() == DRR->getDecl())
|
||||
DiagRuntimeBehavior(Loc, nullptr,
|
||||
PDiag(diag::warn_comparison_always)
|
||||
<< 0 // self-
|
||||
<< 2 // "a constant"
|
||||
);
|
||||
}
|
||||
diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
|
||||
|
||||
// Check for comparisons of floating point operands using != and ==.
|
||||
if (!IsRelational && LHSType->hasFloatingRepresentation()) {
|
||||
if (BinaryOperator::isEqualityOp(Opc) &&
|
||||
LHSType->hasFloatingRepresentation()) {
|
||||
assert(RHS.get()->getType()->hasFloatingRepresentation());
|
||||
CheckFloatComparison(Loc, LHS.get(), RHS.get());
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ static int4 test1() {
|
|||
int4 vec, rv;
|
||||
|
||||
// comparisons to self...
|
||||
return vec == vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec != vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec < vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec <= vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec > vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec >= vec; // expected-warning{{self-comparison always evaluates to a constant}}
|
||||
return vec == vec; // expected-warning{{self-comparison always evaluates to true}}
|
||||
return vec != vec; // expected-warning{{self-comparison always evaluates to false}}
|
||||
return vec < vec; // expected-warning{{self-comparison always evaluates to false}}
|
||||
return vec <= vec; // expected-warning{{self-comparison always evaluates to true}}
|
||||
return vec > vec; // expected-warning{{self-comparison always evaluates to false}}
|
||||
return vec >= vec; // expected-warning{{self-comparison always evaluates to true}}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue