Skip to content

Commit 7347e5e

Browse files
authored
[Clang] Add '-Warray-compare' flag for C++ below version 20 (#118031)
Currently, we support `-wdeprecated-array-compare` for C++20 or above and don't report any warning for older versions, this PR supports `-Warray-compare` for older versions and for GCC compatibility. Fixes #114770
1 parent ee9e786 commit 7347e5e

File tree

8 files changed

+57
-19
lines changed

8 files changed

+57
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ New Compiler Flags
419419
existing ``-fno-c++-static-destructors`` flag) skips all static
420420
destructors registration.
421421

422+
- The ``-Warray-compare`` warning has been added to warn about array comparison
423+
on versions older than C++20.
424+
422425
Deprecated Compiler Flags
423426
-------------------------
424427

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10269,6 +10269,11 @@ def warn_depr_array_comparison : Warning<
1026910269
"to compare array addresses, use unary '+' to decay operands to pointers">,
1027010270
InGroup<DeprecatedArrayCompare>;
1027110271

10272+
def warn_array_comparison : Warning<
10273+
"comparison between two arrays compare their addresses and will be deprecated in c++20; "
10274+
"to compare array addresses, use unary '+' to decay operands to pointers">,
10275+
InGroup<DiagGroup<"array-compare">>;
10276+
1027210277
def warn_stringcompare : Warning<
1027310278
"result of comparison against %select{a string literal|@encode}0 is "
1027410279
"unspecified (use an explicit string comparison function instead)">,

clang/lib/Sema/SemaExpr.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11833,14 +11833,21 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
1183311833
AlwaysEqual, // std::strong_ordering::equal from operator<=>
1183411834
};
1183511835

11836+
// C++1a [array.comp]:
11837+
// Equality and relational comparisons ([expr.eq], [expr.rel]) between two
11838+
// operands of array type.
1183611839
// C++2a [depr.array.comp]:
1183711840
// Equality and relational comparisons ([expr.eq], [expr.rel]) between two
1183811841
// operands of array type are deprecated.
11839-
if (S.getLangOpts().CPlusPlus20 && LHSStripped->getType()->isArrayType() &&
11842+
if (S.getLangOpts().CPlusPlus && LHSStripped->getType()->isArrayType() &&
1184011843
RHSStripped->getType()->isArrayType()) {
11841-
S.Diag(Loc, diag::warn_depr_array_comparison)
11842-
<< LHS->getSourceRange() << RHS->getSourceRange()
11843-
<< LHSStripped->getType() << RHSStripped->getType();
11844+
auto IsDeprArrayComparionIgnored =
11845+
S.getDiagnostics().isIgnored(diag::warn_depr_array_comparison, Loc);
11846+
auto DiagID = !S.getLangOpts().CPlusPlus20 || IsDeprArrayComparionIgnored
11847+
? diag::warn_array_comparison
11848+
: diag::warn_depr_array_comparison;
11849+
S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
11850+
<< LHSStripped->getType() << RHSStripped->getType();
1184411851
// Carry on to produce the tautological comparison warning, if this
1184511852
// expression is potentially-evaluated, we can resolve the array to a
1184611853
// non-weak declaration, and so on.

clang/test/Analysis/reference.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ namespace PR13440 {
8989
S s = { a };
9090
S2 s2 = { a };
9191

92-
if (s.x != a) return;
93-
if (s2.x != a) return;
92+
if (s.x != a) return; // expected-warning {{comparison between two arrays}}
93+
if (s2.x != a) return; // expected-warning {{comparison between two arrays}}
9494

9595
a[0] = 42;
9696
clang_analyzer_eval(s.x[0] == 42); // expected-warning{{TRUE}}

clang/test/Sema/warn-stringcompare.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -x c -fsyntax-only -verify %s
2-
// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cxx %s
33

44
#define DELIM "/"
55
#define DOT "."
@@ -15,15 +15,15 @@ void test(const char *d) {
1515
if (NULL == "/")
1616
return;
1717
if ("/" != DELIM) // expected-warning {{result of comparison against a string literal is unspecified (use an explicit string comparison function instead)}}
18-
return;
18+
return; // cxx-warning@-1 {{comparison between two arrays}}
1919
if (DELIM == "/") // expected-warning {{result of comparison against a string literal is unspecified (use an explicit string comparison function instead)}}
20-
return;
20+
return; // cxx-warning@-1 {{comparison between two arrays}}
2121
if (DELIM != NULL)
2222
return;
2323
if (NULL == DELIM)
2424
return;
2525
if (DOT != DELIM) // expected-warning {{result of comparison against a string literal is unspecified (use an explicit string comparison function instead)}}
26-
return;
26+
return; // cxx-warning@-1 {{comparison between two arrays}}
2727
if (DELIM == DOT) // expected-warning {{result of comparison against a string literal is unspecified (use an explicit string comparison function instead)}}
28-
return;
28+
return; // cxx-warning@-1 {{comparison between two arrays}}
2929
}

clang/test/SemaCXX/deprecated.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,19 @@ namespace ArithConv {
246246

247247
namespace ArrayComp {
248248
int arr1[3], arr2[4];
249-
bool b1 = arr1 == arr2; // expected-warning {{array comparison always evaluates to false}} cxx20-warning {{comparison between two arrays is deprecated}}
250-
bool b2 = arr1 < arr2; // expected-warning {{array comparison always evaluates to a constant}} cxx20-warning {{comparison between two arrays is deprecated}}
249+
bool b1 = arr1 == arr2; // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
250+
// expected-warning@-1 {{array comparison always evaluates to false}}
251+
bool b2 = arr1 < arr2; // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
252+
// expected-warning@-1 {{array comparison always evaluates to a constant}}
251253
__attribute__((weak)) int arr3[3];
252-
bool b3 = arr1 == arr3; // cxx20-warning {{comparison between two arrays is deprecated}}
253-
bool b4 = arr1 < arr3; // cxx20-warning {{comparison between two arrays is deprecated}}
254+
bool b3 = arr1 == arr3; // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
255+
bool b4 = arr1 < arr3; // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
254256
#if __cplusplus > 201703L
255257
bool b5 = arr1 <=> arr2; // cxx20-error {{invalid operands}}
256258
#endif
257259

258260
int (&f())[3];
259-
bool b6 = arr1 == f(); // cxx20-warning {{comparison between two arrays is deprecated}}
261+
bool b6 = arr1 == f(); // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
260262
bool b7 = arr1 == +f();
261263
}
262264

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -verify=expected,not-cxx20
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wno-deprecated-array-compare -verify %s -verify=expected,not-cxx20
3+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wdeprecated -verify %s -verify=expected,cxx20
4+
5+
typedef struct {
6+
char str[16];
7+
int id[16];
8+
} Object;
9+
10+
bool object_equal(const Object &obj1, const Object &obj2) {
11+
if (obj1.str != obj2.str) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
12+
return false;
13+
if (obj1.id != obj2.id) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
14+
return false;
15+
return true;
16+
}
17+
18+
19+
void foo(int (&array1)[2], int (&array2)[2]) {
20+
if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
21+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s
2-
// expected-no-diagnostics
1+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s -verify=expected,not-cxx20
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wdeprecated -verify %s -verify=expected,cxx20
33

44
void f(int (&array1)[2], int (&array2)[2]) {
5-
if (array1 == array2) { } // no warning
5+
if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}}
66
}

0 commit comments

Comments
 (0)