InGroup<DiagGroup<"unused-volatile-lvalue">>;
def warn_unused_comparison : Warning<
- "%select{equality|inequality}0 comparison result unused">,
+ "%select{%select{|in}1equality|relational}0 comparison result unused">,
InGroup<UnusedComparison>;
def note_inequality_comparison_to_or_assign : Note<
"use '|=' to turn this inequality comparison into an or-assignment">;
return true;
case CXXOperatorCallExprClass: {
- // We warn about operator== and operator!= even when user-defined operator
+ // Warn about operator ==,!=,<,>,<=, and >= even when user-defined operator
// overloads as there is no reasonable way to define these such that they
// have non-trivial, desirable side-effects. See the -Wunused-comparison
- // warning: these operators are commonly typo'ed, and so warning on them
+ // warning: operators == and != are commonly typo'ed, and so warning on them
// provides additional value as well. If this list is updated,
// DiagnoseUnusedComparison should be as well.
const CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(this);
- if (Op->getOperator() == OO_EqualEqual ||
- Op->getOperator() == OO_ExclaimEqual) {
+ switch (Op->getOperator()) {
+ default:
+ break;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ case OO_Less:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_LessEqual:
WarnE = this;
Loc = Op->getOperatorLoc();
R1 = Op->getSourceRange();
}
}
-/// \brief Diagnose unused '==' and '!=' as likely typos for '=' or '|='.
+/// \brief Diagnose unused comparisons, both builtin and overloaded operators.
+/// For '==' and '!=', suggest fixits for '=' or '|='.
///
/// Adding a cast to void (or other expression wrappers) will prevent the
/// warning from firing.
static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
SourceLocation Loc;
- bool IsNotEqual, CanAssign;
+ bool IsNotEqual, CanAssign, IsRelational;
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
- if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE)
+ if (!Op->isComparisonOp())
return false;
+ IsRelational = Op->isRelationalOp();
Loc = Op->getOperatorLoc();
IsNotEqual = Op->getOpcode() == BO_NE;
CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
} else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
- if (Op->getOperator() != OO_EqualEqual &&
- Op->getOperator() != OO_ExclaimEqual)
+ switch (Op->getOperator()) {
+ default:
return false;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ IsRelational = false;
+ break;
+ case OO_Less:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_LessEqual:
+ IsRelational = true;
+ break;
+ }
Loc = Op->getOperatorLoc();
IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
return false;
S.Diag(Loc, diag::warn_unused_comparison)
- << (unsigned)IsNotEqual << E->getSourceRange();
+ << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange();
// If the LHS is a plausible entity to assign to, provide a fixit hint to
// correct common typos.
- if (CanAssign) {
+ if (!IsRelational && CanAssign) {
if (IsNotEqual)
S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
<< FixItHint::CreateReplacement(Loc, "|=");
void bar(volatile int *VP, int *P, int A,
_Complex double C, volatile _Complex double VC) {
- VP < P; // expected-warning {{expression result unused}}
+ VP < P; // expected-warning {{relational comparison result unused}}
(void)A;
(void)foo(1,2); // no warning.
- A < foo(1, 2); // expected-warning {{expression result unused}}
+ A < foo(1, 2); // expected-warning {{relational comparison result unused}}
foo(1,2)+foo(4,3); // expected-warning {{expression result unused}}
int b = 0;
if (a)
- b < 1; // expected-warning{{expression result unused}}
+ b < 1; // expected-warning{{relational comparison result unused}}
else
- b < 2; // expected-warning{{expression result unused}}
+ b < 2; // expected-warning{{relational comparison result unused}}
while (1)
- b < 3; // expected-warning{{expression result unused}}
+ b < 3; // expected-warning{{relational comparison result unused}}
do
- b < 4; // expected-warning{{expression result unused}}
+ b < 4; // expected-warning{{relational comparison result unused}}
while (1);
for (;;)
- b < 5; // expected-warning{{expression result unused}}
+ b < 5; // expected-warning{{relational comparison result unused}}
- for (b < 1;;) {} // expected-warning{{expression result unused}}
+ for (b < 1;;) {} // expected-warning{{relational comparison result unused}}
for (;b < 1;) {}
- for (;;b < 1) {} // expected-warning{{expression result unused}}
+ for (;;b < 1) {} // expected-warning{{relational comparison result unused}}
}
// rdar://7186119
__declspec(property(get=GetV, put=SetV)) T V;
T GetV() { return 0; }
void SetV(T v) {}
- void f() { V = this->V; V < this->V; }
+ bool f() { V = this->V; return V < this->V; }
void g() { V++; }
void h() { V*=2; }
};
struct A {
bool operator==(const A&);
bool operator!=(const A&);
+ bool operator<(const A&);
+ bool operator>(const A&);
+ bool operator<=(const A&);
+ bool operator>=(const A&);
A operator|=(const A&);
operator bool();
};
// expected-note {{use '=' to turn this equality comparison into an assignment}}
x != 7; // expected-warning {{inequality comparison result unused}} \
// expected-note {{use '|=' to turn this inequality comparison into an or-assignment}}
+ x < 7; // expected-warning {{relational comparison result unused}}
+ x > 7; // expected-warning {{relational comparison result unused}}
+ x <= 7; // expected-warning {{relational comparison result unused}}
+ x >= 7; // expected-warning {{relational comparison result unused}}
+
7 == x; // expected-warning {{equality comparison result unused}}
p == p; // expected-warning {{equality comparison result unused}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}}
a != b; // expected-warning {{inequality comparison result unused}} \
// expected-note {{use '|=' to turn this inequality comparison into an or-assignment}}
+ a < b; // expected-warning {{relational comparison result unused}}
+ a > b; // expected-warning {{relational comparison result unused}}
+ a <= b; // expected-warning {{relational comparison result unused}}
+ a >= b; // expected-warning {{relational comparison result unused}}
+
A() == b; // expected-warning {{equality comparison result unused}}
if (42) x == 7; // expected-warning {{equality comparison result unused}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}}
b = (void (*)()) twoT<int>;
one < one; //expected-warning {{self-comparison always evaluates to false}} \
- //expected-warning {{expression result unused}}
+ //expected-warning {{relational comparison result unused}}
oneT<int> < oneT<int>; //expected-warning {{self-comparison always evaluates to false}} \
- //expected-warning {{expression result unused}}
+ //expected-warning {{relational comparison result unused}}
two < two; //expected-error 2 {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{invalid operands to binary expression ('void' and 'void')}}
twoT<int> < twoT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}}