112 lines
5.4 KiB
Diff
112 lines
5.4 KiB
Diff
|
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
|
||
|
index fea0fe1..1046972 100644
|
||
|
--- tools/clang/lib/Sema/SemaExpr.cpp
|
||
|
+++ tools/clang/lib/Sema/SemaExpr.cpp
|
||
|
@@ -6577,23 +6577,29 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||
|
checkEnumComparison(*this, Loc, LHS, RHS);
|
||
|
|
||
|
if (!LHSType->hasFloatingRepresentation() &&
|
||
|
- !(LHSType->isBlockPointerType() && IsRelational) &&
|
||
|
- !LHS.get()->getLocStart().isMacroID() &&
|
||
|
- !RHS.get()->getLocStart().isMacroID()) {
|
||
|
+ !(LHSType->isBlockPointerType() && IsRelational)) {
|
||
|
// 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.
|
||
|
//
|
||
|
- // NOTE: Don't warn about comparison expressions resulting from macro
|
||
|
- // expansion. Also don't warn about comparisons which are only self
|
||
|
+ // NOTE: Don't warn about self-comparison expressions resulting from macro
|
||
|
+ // expansion, unless they don't make sense at all.
|
||
|
+ // Also don't warn about comparisons which are only self
|
||
|
// comparisons within a template specialization. The warnings should catch
|
||
|
// obvious cases in the definition of the template anyways. The idea is to
|
||
|
// warn when the typed comparison operator will always evaluate to the same
|
||
|
// result.
|
||
|
+ bool InMacro = LHS.get()->getLocStart().isMacroID() ||
|
||
|
+ RHS.get()->getLocStart().isMacroID();
|
||
|
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) {
|
||
|
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
|
||
|
+ if (isa<CastExpr>(LHSStripped))
|
||
|
+ LHSStripped = LHSStripped->IgnoreParenCasts();
|
||
|
if (DRL->getDecl() == DRR->getDecl() &&
|
||
|
- !IsWithinTemplateSpecialization(DRL->getDecl())) {
|
||
|
+ !IsWithinTemplateSpecialization(DRL->getDecl()) &&
|
||
|
+ !InMacro &&
|
||
|
+ !isa<StringLiteral>(LHSStripped) &&
|
||
|
+ !isa<ObjCEncodeExpr>(LHSStripped)) {
|
||
|
DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
|
||
|
<< 0 // self-
|
||
|
<< (Opc == BO_EQ
|
||
|
@@ -6602,23 +6608,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
|
||
|
} else if (LHSType->isArrayType() && RHSType->isArrayType() &&
|
||
|
!DRL->getDecl()->getType()->isReferenceType() &&
|
||
|
!DRR->getDecl()->getType()->isReferenceType()) {
|
||
|
- // what is it always going to eval to?
|
||
|
- char always_evals_to;
|
||
|
switch(Opc) {
|
||
|
case BO_EQ: // e.g. array1 == array2
|
||
|
- always_evals_to = 0; // false
|
||
|
+ if (!InMacro)
|
||
|
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
|
||
|
+ << 1 // array
|
||
|
+ << 0 /* evaluates to false */ );
|
||
|
break;
|
||
|
case BO_NE: // e.g. array1 != array2
|
||
|
- always_evals_to = 1; // true
|
||
|
+ if (!InMacro)
|
||
|
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
|
||
|
+ << 1 // array
|
||
|
+ << 1 /* evaluates to true */ );
|
||
|
break;
|
||
|
- default:
|
||
|
+ default: // e.g. array1 <= array2
|
||
|
// best we can say is 'a constant'
|
||
|
- always_evals_to = 2; // e.g. array1 <= array2
|
||
|
+ DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
|
||
|
+ << 1 // array
|
||
|
+ << 2 /* evaluates to constant */ );
|
||
|
break;
|
||
|
}
|
||
|
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
|
||
|
- << 1 // array
|
||
|
- << always_evals_to);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
|
||
|
index 72cff65..b17b6ec 100644
|
||
|
--- tools/clang/test/Sema/exprs.c
|
||
|
+++ tools/clang/test/Sema/exprs.c
|
||
|
@@ -125,6 +125,12 @@ int test12b(const char *X) {
|
||
|
return sizeof(X == "foo"); // no-warning
|
||
|
}
|
||
|
|
||
|
+// PR12463
|
||
|
+#define FOO_LITERAL "foo"
|
||
|
+int test12c(const char *X) {
|
||
|
+ return X == FOO_LITERAL; // expected-warning {{comparison against a string literal is unspecified (use strncmp instead)}}
|
||
|
+}
|
||
|
+
|
||
|
// rdar://6719156
|
||
|
void test13(
|
||
|
void (^P)()) { // expected-error {{blocks support disabled - compile with -fblocks}}
|
||
|
diff --git a/test/Sema/self-comparison.c b/test/Sema/self-comparison.c
|
||
|
index edb3a6a..8679a3f 100644
|
||
|
--- tools/clang/test/Sema/self-comparison.c
|
||
|
+++ tools/clang/test/Sema/self-comparison.c
|
||
|
@@ -72,6 +72,13 @@ int array_comparisons() {
|
||
|
return array1 <= array2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
return array1 > array2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
return array1 >= array2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
+ // Issue a warning for this even if macro expansion is involved (PR12463)
|
||
|
+#define ARRAY1 array1
|
||
|
+#define ARRAY2 array2
|
||
|
+ return ARRAY1 < ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
+ return ARRAY1 <= ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
+ return ARRAY1 > ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
+ return ARRAY1 >= ARRAY2; // expected-warning{{array comparison always evaluates to a constant}}
|
||
|
|
||
|
}
|
||
|
|