Skip to content

Commit ec170db

Browse files
committed
Warn about comparisons between arrays and improve self-comparison
warnings, from Troy Straszheim! Fixes PR6163. llvm-svn: 105631
1 parent 61b5ff5 commit ec170db

File tree

7 files changed

+137
-17
lines changed

7 files changed

+137
-17
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,8 +2917,10 @@ def err_ret_local_block : Error<
29172917

29182918
// For non-floating point, expressions of the form x == x or x != x
29192919
// should result in a warning, since these always evaluate to a constant.
2920-
def warn_selfcomparison : Warning<
2921-
"self-comparison always results in a constant value">;
2920+
// Array comparisons have similar warnings
2921+
def warn_comparison_always : Warning<
2922+
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">;
2923+
29222924
def warn_stringcompare : Warning<
29232925
"result of comparison against %select{a string literal|@encode}0 is "
29242926
"unspecified (use strncmp instead)">;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5292,13 +5292,6 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
52925292
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
52935293
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
52945294

5295-
// C99 6.5.8p3 / C99 6.5.9p4
5296-
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
5297-
UsualArithmeticConversions(lex, rex);
5298-
else {
5299-
UsualUnaryConversions(lex);
5300-
UsualUnaryConversions(rex);
5301-
}
53025295
QualType lType = lex->getType();
53035296
QualType rType = rex->getType();
53045297

@@ -5312,10 +5305,36 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
53125305
Expr *LHSStripped = lex->IgnoreParens();
53135306
Expr *RHSStripped = rex->IgnoreParens();
53145307
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped))
5315-
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped))
5308+
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
53165309
if (DRL->getDecl() == DRR->getDecl() &&
5317-
!isa<EnumConstantDecl>(DRL->getDecl()))
5318-
DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
5310+
!isa<EnumConstantDecl>(DRL->getDecl())) {
5311+
DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always)
5312+
<< 0 // self-
5313+
<< (Opc == BinaryOperator::EQ
5314+
|| Opc == BinaryOperator::LE
5315+
|| Opc == BinaryOperator::GE));
5316+
} else if (lType->isArrayType() && rType->isArrayType() &&
5317+
!DRL->getDecl()->getType()->isReferenceType() &&
5318+
!DRR->getDecl()->getType()->isReferenceType()) {
5319+
// what is it always going to eval to?
5320+
char always_evals_to;
5321+
switch(Opc) {
5322+
case BinaryOperator::EQ: // e.g. array1 == array2
5323+
always_evals_to = 0; // false
5324+
break;
5325+
case BinaryOperator::NE: // e.g. array1 != array2
5326+
always_evals_to = 1; // true
5327+
break;
5328+
default:
5329+
// best we can say is 'a constant'
5330+
always_evals_to = 2; // e.g. array1 <= array2
5331+
break;
5332+
}
5333+
DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always)
5334+
<< 1 // array
5335+
<< always_evals_to);
5336+
}
5337+
}
53195338

53205339
if (isa<CastExpr>(LHSStripped))
53215340
LHSStripped = LHSStripped->IgnoreParenCasts();
@@ -5358,6 +5377,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
53585377
}
53595378
}
53605379

5380+
// C99 6.5.8p3 / C99 6.5.9p4
5381+
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
5382+
UsualArithmeticConversions(lex, rex);
5383+
else {
5384+
UsualUnaryConversions(lex);
5385+
UsualUnaryConversions(rex);
5386+
}
5387+
5388+
lType = lex->getType();
5389+
rType = rex->getType();
5390+
53615391
// The result of comparisons is 'bool' in C++, 'int' in C.
53625392
QualType ResultTy = getLangOptions().CPlusPlus ? Context.BoolTy:Context.IntTy;
53635393

@@ -5632,7 +5662,11 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
56325662
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
56335663
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
56345664
if (DRL->getDecl() == DRR->getDecl())
5635-
DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
5665+
DiagRuntimeBehavior(Loc,
5666+
PDiag(diag::warn_comparison_always)
5667+
<< 0 // self-
5668+
<< 2 // "a constant"
5669+
);
56365670
}
56375671

56385672
// Check for comparisons of floating point operands using != and ==.

clang/test/Sema/compare.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
int test(char *C) { // nothing here should warn.
44
return C != ((void*)0);
55
return C != (void*)0;
6-
return C != 0;
6+
return C != 0;
77
return C != 1; // expected-warning {{comparison between pointer and integer ('char *' and 'int')}}
88
}
99

@@ -218,7 +218,7 @@ int pointers(int *a) {
218218

219219
int function_pointers(int (*a)(int), int (*b)(int), void (*c)(int)) {
220220
return a > b; // expected-warning {{ordered comparison of function pointers}}
221-
return function_pointers > function_pointers; // expected-warning {{ordered comparison of function pointers}}
221+
return function_pointers > function_pointers; // expected-warning {{self-comparison always evaluates to false}} expected-warning{{ordered comparison of function pointers}}
222222
return a > c; // expected-warning {{comparison of distinct pointer types}}
223223
return a == (void *) 0;
224224
return a == (void *) 1; // expected-warning {{equality comparison between function pointer and void pointer}}
@@ -229,6 +229,7 @@ int void_pointers(void* foo) {
229229
return foo == (void*) 1;
230230
}
231231

232+
232233
int test1(int i) {
233234
enum en { zero };
234235
return i > zero;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unreachable-code %s
2+
3+
typedef __attribute__(( ext_vector_type(4) )) int int4;
4+
5+
static int4 test1() {
6+
int4 vec, rv;
7+
8+
// comparisons to self...
9+
return vec == vec; // expected-warning{{self-comparison always evaluates to a constant}}
10+
return vec != vec; // expected-warning{{self-comparison always evaluates to a constant}}
11+
return vec < vec; // expected-warning{{self-comparison always evaluates to a constant}}
12+
return vec <= vec; // expected-warning{{self-comparison always evaluates to a constant}}
13+
return vec > vec; // expected-warning{{self-comparison always evaluates to a constant}}
14+
return vec >= vec; // expected-warning{{self-comparison always evaluates to a constant}}
15+
}
16+
17+
18+
typedef __attribute__(( ext_vector_type(4) )) float float4;
19+
20+
static int4 test2() {
21+
float4 vec, rv;
22+
23+
// comparisons to self. no warning, they're floats
24+
return vec == vec; // no-warning
25+
return vec != vec; // no-warning
26+
return vec < vec; // no-warning
27+
return vec <= vec; // no-warning
28+
return vec > vec; // no-warning
29+
return vec >= vec; // no-warning
30+
}

clang/test/Sema/self-comparison.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22

33
int foo(int x) {
4-
return x == x; // expected-warning {{self-comparison always results}}
4+
return x == x; // expected-warning {{self-comparison always evaluates to true}}
55
}
66

77
int foo2(int x) {
8-
return (x) != (((x))); // expected-warning {{self-comparison always results}}
8+
return (x) != (((x))); // expected-warning {{self-comparison always evaluates to false}}
9+
}
10+
11+
void foo3(short s, short t) {
12+
if (s == s) {} // expected-warning {{self-comparison always evaluates to true}}
13+
if (s == t) {} // no-warning
14+
}
15+
16+
void foo4(void* v, void* w) {
17+
if (v == v) {} // expected-warning {{self-comparison always evaluates to true}}
18+
if (v == w) {} // no-warning
919
}
1020

1121
int qux(int x) {
@@ -36,3 +46,34 @@ int compare_enum() {
3646
int compare_sizeof(int x) {
3747
return sizeof(x == x); // no-warning
3848
}
49+
50+
int array_comparisons() {
51+
int array1[2];
52+
int array2[2];
53+
54+
//
55+
// compare same array
56+
//
57+
return array1 == array1; // expected-warning{{self-comparison always evaluates to true}}
58+
return array1 != array1; // expected-warning{{self-comparison always evaluates to false}}
59+
return array1 < array1; // expected-warning{{self-comparison always evaluates to false}}
60+
return array1 <= array1; // expected-warning{{self-comparison always evaluates to true}}
61+
return array1 > array1; // expected-warning{{self-comparison always evaluates to false}}
62+
return array1 >= array1; // expected-warning{{self-comparison always evaluates to true}}
63+
64+
//
65+
// compare differrent arrays
66+
//
67+
return array1 == array2; // expected-warning{{array comparison always evaluates to false}}
68+
return array1 != array2; // expected-warning{{array comparison always evaluates to true}}
69+
70+
//
71+
// we don't know what these are going to be
72+
//
73+
return array1 < array2; // expected-warning{{array comparison always evaluates to a constant}}
74+
return array1 <= array2; // expected-warning{{array comparison always evaluates to a constant}}
75+
return array1 > array2; // expected-warning{{array comparison always evaluates to a constant}}
76+
return array1 >= array2; // expected-warning{{array comparison always evaluates to a constant}}
77+
78+
}
79+

clang/test/SemaCXX/overloaded-operator.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ struct B {
4949
}
5050
};
5151

52+
// we shouldn't see warnings about self-comparison,
53+
// this is a member function, we dunno what it'll do
54+
bool i(B b)
55+
{
56+
return b == b;
57+
}
58+
5259
enum Enum1 { };
5360
enum Enum2 { };
5461

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
void f(int (&array1)[2], int (&array2)[2]) {
4+
if (array1 == array2) { } // no warning
5+
}

0 commit comments

Comments
 (0)