From 1be869072e4ab7ef9eee8b47ed65a4ad025a10f8 Mon Sep 17 00:00:00 2001 From: Mohit Mishra Date: Sun, 25 Oct 2026 11:48:52 +0530 Subject: [PATCH 1/3] Diagnose a comparison between two arrays: deprecated in C++20, not allowed in C++26. [GH #370] --- src/error_msg.txt | 2 ++ src/expr.c | 26 +++++++++++++++++++ .../gh-370-array-comparisons.txt | 12 +++++++++ .../tests/changes/.GH370.rto/default.1.1.txt | 18 +++++++++++++ .../tests/changes/.GH370.rto/default.2.1.txt | 18 +++++++++++++ .../tests/changes/.GH370.rto/default.3.1.txt | 18 +++++++++++++ .../changes/.GH370_a.rto/default.1.1.txt | 17 ++++++++++++ .../changes/.GH370_a.rto/default.2.1.txt | 17 ++++++++++++ .../changes/.GH370_a.rto/default.3.1.txt | 17 ++++++++++++ .../changes/.GH370_a.rto/default.4.1.txt | 1 + tests/tests/changes/GH370.sft.cpp | 16 ++++++++++++ tests/tests/changes/GH370_a.sft.cpp | 18 +++++++++++++ 12 files changed, 180 insertions(+) create mode 100644 src/pending_changes/gh-370-array-comparisons.txt create mode 100644 tests/tests/changes/.GH370.rto/default.1.1.txt create mode 100644 tests/tests/changes/.GH370.rto/default.2.1.txt create mode 100644 tests/tests/changes/.GH370.rto/default.3.1.txt create mode 100644 tests/tests/changes/.GH370_a.rto/default.1.1.txt create mode 100644 tests/tests/changes/.GH370_a.rto/default.2.1.txt create mode 100644 tests/tests/changes/.GH370_a.rto/default.3.1.txt create mode 100644 tests/tests/changes/.GH370_a.rto/default.4.1.txt create mode 100644 tests/tests/changes/GH370.sft.cpp create mode 100644 tests/tests/changes/GH370_a.sft.cpp diff --git a/src/error_msg.txt b/src/error_msg.txt index 089cac9e4c..812ee170c2 100644 --- a/src/error_msg.txt +++ b/src/error_msg.txt @@ -3679,5 +3679,7 @@ ec_exp_interpolator;;"expected an interpolator (\"\\[\", \"\\[:\", \"\\{\", \"\\ ec_interpolated_id_is_not_identifier;;"%sq does not spell an identifier" ec_interpolated_operand_is_not_token_sequence;;"the operand of a \"\\{...}\" interpolator is not a token sequence" ec_tag_redefined_differently;;"this declaration of %n does not declare the same type as the declaration %p" +ec_array_comparison_deprecated;;"comparison between two arrays is deprecated" +ec_array_comparison_not_allowed;;"comparison between two arrays is not allowed" ############################################################################### diff --git a/src/expr.c b/src/expr.c index 67283dbc3a..4394deae12 100644 --- a/src/expr.c +++ b/src/expr.c @@ -32487,6 +32487,30 @@ different enum types (or, in C, have different affiliated enum types). } /* diagnose_comparison_if_different_enum_types */ +static void check_for_array_comparison(an_operand *opnd1, + an_operand *opnd2, + a_source_position *operator_pos) +/* +opnd1 and opnd2 are the operands of a built-in equality or relational +operator at operator_pos, before the array-to-pointer conversion. If both +have array type, issue a diagnostic: such comparisons are deprecated in C++20 +and not allowed in C++26 (P2865). +*/ +{ + if (cpp20_mode && is_array_type(opnd1->type) && + is_array_type(opnd2->type)) { + if (cpp26_mode && !gpp_version_is(<150000) && + !clangcpp_version_is(<200000)) { + /* GCC 15 and Clang 20 implement P2865. Earlier versions only issue a + deprecation warning. */ + expr_pos_error(ec_array_comparison_not_allowed, operator_pos); + } else { + expr_pos_warning(ec_array_comparison_deprecated, operator_pos); + } /* if */ + } /* if */ +} /* check_for_array_comparison */ + + static void process_rel_operator(an_operand *opnd1, an_operand *opnd2, a_token_kind operator_token, @@ -32532,6 +32556,7 @@ describe the location of the operator. } /* if */ if (!processed) { /* Non-operator-function cases. */ + check_for_array_comparison(opnd1, opnd2, operator_pos); /* The first operand must be an arithmetic or enum type or a pointer. */ do_operand_transformations(opnd1, TOPT_NO_OPTIONS); opnd1_is_pointer = FALSE; @@ -33036,6 +33061,7 @@ operator_tsn describe the location of the operator. } /* if */ if (!processed) { /* Non-operator-function cases. */ + check_for_array_comparison(opnd1, opnd2, operator_pos); /* The first operand must be an arithmetic or enum type or a pointer. */ do_operand_transformations(opnd1, TOPT_NO_OPTIONS); if (is_arithmetic_or_enum_type(opnd1->type)) { diff --git a/src/pending_changes/gh-370-array-comparisons.txt b/src/pending_changes/gh-370-array-comparisons.txt new file mode 100644 index 0000000000..6b7fcc443e --- /dev/null +++ b/src/pending_changes/gh-370-array-comparisons.txt @@ -0,0 +1,12 @@ +[GH #370] +C++26: comparison between two arrays is not allowed + +A comparison between two arrays using an equality or relational operator is +deprecated in C++20 and not allowed in C++26 (P2865). The front end did not +diagnose it. It is now a warning in C++20 and C++23, and an error in C++26 +(only a warning when emulating GCC versions before 15 or Clang versions before +20, which do the same). For example, with --c++26: + + int a[2], b[2]; + bool x = a == b; // Now an error. + bool y = a == &b[0]; // Okay: one operand is a pointer. diff --git a/tests/tests/changes/.GH370.rto/default.1.1.txt b/tests/tests/changes/.GH370.rto/default.1.1.txt new file mode 100644 index 0000000000..9e70431e0d --- /dev/null +++ b/tests/tests/changes/.GH370.rto/default.1.1.txt @@ -0,0 +1,18 @@ +fe_only -DTEST_NUMBER=1 --c++26 Test_name.c +"Test_name.c", line 10: error: comparison between two arrays is not allowed + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 11: error: comparison between two arrays is not allowed + bool x2 = a != b; + ^ + +"Test_name.c", line 12: error: comparison between two arrays is not allowed + bool x3 = a < b; + ^ + +"Test_name.c", line 13: error: comparison between two arrays is not allowed + bool x4 = a >= b; + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370.rto/default.2.1.txt b/tests/tests/changes/.GH370.rto/default.2.1.txt new file mode 100644 index 0000000000..c5c121f800 --- /dev/null +++ b/tests/tests/changes/.GH370.rto/default.2.1.txt @@ -0,0 +1,18 @@ +fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 150000 Test_name.c +"Test_name.c", line 10: error: comparison between two arrays is not allowed + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 11: error: comparison between two arrays is not allowed + bool x2 = a != b; + ^ + +"Test_name.c", line 12: error: comparison between two arrays is not allowed + bool x3 = a < b; + ^ + +"Test_name.c", line 13: error: comparison between two arrays is not allowed + bool x4 = a >= b; + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370.rto/default.3.1.txt b/tests/tests/changes/.GH370.rto/default.3.1.txt new file mode 100644 index 0000000000..362ad30717 --- /dev/null +++ b/tests/tests/changes/.GH370.rto/default.3.1.txt @@ -0,0 +1,18 @@ +fe_only -DTEST_NUMBER=3 --c++26 --clang_version 200000 Test_name.c +"Test_name.c", line 10: error: comparison between two arrays is not allowed + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 11: error: comparison between two arrays is not allowed + bool x2 = a != b; + ^ + +"Test_name.c", line 12: error: comparison between two arrays is not allowed + bool x3 = a < b; + ^ + +"Test_name.c", line 13: error: comparison between two arrays is not allowed + bool x4 = a >= b; + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370_a.rto/default.1.1.txt b/tests/tests/changes/.GH370_a.rto/default.1.1.txt new file mode 100644 index 0000000000..419dfbbb82 --- /dev/null +++ b/tests/tests/changes/.GH370_a.rto/default.1.1.txt @@ -0,0 +1,17 @@ +fe_only -DTEST_NUMBER=1 --c++20 Test_name.c +"Test_name.c", line 12: warning: comparison between two arrays is deprecated + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 13: warning: comparison between two arrays is deprecated + bool x2 = a != b; + ^ + +"Test_name.c", line 14: warning: comparison between two arrays is deprecated + bool x3 = a < b; + ^ + +"Test_name.c", line 15: warning: comparison between two arrays is deprecated + bool x4 = a >= b; + ^ + diff --git a/tests/tests/changes/.GH370_a.rto/default.2.1.txt b/tests/tests/changes/.GH370_a.rto/default.2.1.txt new file mode 100644 index 0000000000..e498f3a769 --- /dev/null +++ b/tests/tests/changes/.GH370_a.rto/default.2.1.txt @@ -0,0 +1,17 @@ +fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 140000 Test_name.c +"Test_name.c", line 12: warning: comparison between two arrays is deprecated + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 13: warning: comparison between two arrays is deprecated + bool x2 = a != b; + ^ + +"Test_name.c", line 14: warning: comparison between two arrays is deprecated + bool x3 = a < b; + ^ + +"Test_name.c", line 15: warning: comparison between two arrays is deprecated + bool x4 = a >= b; + ^ + diff --git a/tests/tests/changes/.GH370_a.rto/default.3.1.txt b/tests/tests/changes/.GH370_a.rto/default.3.1.txt new file mode 100644 index 0000000000..1879b074b9 --- /dev/null +++ b/tests/tests/changes/.GH370_a.rto/default.3.1.txt @@ -0,0 +1,17 @@ +fe_only -DTEST_NUMBER=3 --c++26 --clang_version 190000 Test_name.c +"Test_name.c", line 12: warning: comparison between two arrays is deprecated + bool x1 = a == b; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 13: warning: comparison between two arrays is deprecated + bool x2 = a != b; + ^ + +"Test_name.c", line 14: warning: comparison between two arrays is deprecated + bool x3 = a < b; + ^ + +"Test_name.c", line 15: warning: comparison between two arrays is deprecated + bool x4 = a >= b; + ^ + diff --git a/tests/tests/changes/.GH370_a.rto/default.4.1.txt b/tests/tests/changes/.GH370_a.rto/default.4.1.txt new file mode 100644 index 0000000000..21beb60458 --- /dev/null +++ b/tests/tests/changes/.GH370_a.rto/default.4.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=4 --c++17 Test_name.c diff --git a/tests/tests/changes/GH370.sft.cpp b/tests/tests/changes/GH370.sft.cpp new file mode 100644 index 0000000000..5a7750ef79 --- /dev/null +++ b/tests/tests/changes/GH370.sft.cpp @@ -0,0 +1,16 @@ +//type:fn +//options:--c++26:--c++26 --gnu_version 150000:--c++26 --clang_version 200000 +//remark:[GH #370] C++26: comparison between two arrays is not allowed +// +// P2865 makes a comparison between two arrays ill-formed in C++26. + +int a[2], b[2]; +int *p = b; + +bool x1 = a == b; // Two arrays: diagnosed. +bool x2 = a != b; +bool x3 = a < b; +bool x4 = a >= b; + +bool y1 = a == p; // Array and pointer: not diagnosed. +bool y2 = p < a; diff --git a/tests/tests/changes/GH370_a.sft.cpp b/tests/tests/changes/GH370_a.sft.cpp new file mode 100644 index 0000000000..8a8d82148f --- /dev/null +++ b/tests/tests/changes/GH370_a.sft.cpp @@ -0,0 +1,18 @@ +//type:fp +//options:--c++20:--c++26 --gnu_version 140000:--c++26 --clang_version 190000:--c++17 +//remark:[GH #370] Comparison between two arrays is deprecated in C++20 +// +// A comparison between two arrays is deprecated in C++20 and C++23. When +// emulating GCC before 15 or Clang before 20, it is also only deprecated in +// C++26. Before C++20 it is not diagnosed. + +int a[2], b[2]; +int *p = b; + +bool x1 = a == b; // Two arrays: diagnosed. +bool x2 = a != b; +bool x3 = a < b; +bool x4 = a >= b; + +bool y1 = a == p; // Array and pointer: not diagnosed. +bool y2 = p < a; From 21473df5b5c7c31719b2fcb724ee2aa7b010cce9 Mon Sep 17 00:00:00 2001 From: Mohit Mishra Date: Sun, 25 Oct 2026 18:12:09 +0530 Subject: [PATCH 2/3] Update recordings for the new array comparison diagnostics. [GH #370] --- tests/expectations/edg_x86_64/imported.log | 2 -- .../SemaCXX/.deprecated.rto/default.8.1.txt | 20 +++++++++++++++++++ .../SemaCXX/.deprecated.rto/default.9.1.txt | 20 +++++++++++++++++++ .../.self-comparison.rto/default.1.1.txt | 20 +++++++++++++++++++ .../.self-comparison.rto/default.2.1.txt | 20 +++++++++++++++++++ .../.warn-array-comparion.rto/default.2.1.txt | 12 +++++++++++ .../.warn-array-comparion.rto/default.3.1.txt | 12 +++++++++++ .../.warn-array-comparion.rto/default.4.1.txt | 13 ++++++++++++ .../default.2.1.txt | 4 ++++ .../default.3.1.txt | 5 +++++ 10 files changed, 126 insertions(+), 2 deletions(-) diff --git a/tests/expectations/edg_x86_64/imported.log b/tests/expectations/edg_x86_64/imported.log index 34aec5db66..63f4190b17 100644 --- a/tests/expectations/edg_x86_64/imported.log +++ b/tests/expectations/edg_x86_64/imported.log @@ -1441,7 +1441,6 @@ clang/cpp/SemaCXX/vtordisp-mode.sft.cpp:fp:-DTEST_NUMBER=3 --c++11 -DVTORDISP_MO clang/cpp/SemaCXX/warn-array-comparion.sft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL: clang/cpp/SemaCXX/warn-array-comparion.sft.cpp:fn:-DTEST_NUMBER=2 --c++20:FAIL: clang/cpp/SemaCXX/warn-array-comparion.sft.cpp:fn:-DTEST_NUMBER=3 --c++20:FAIL: -clang/cpp/SemaCXX/warn-array-comparion.sft.cpp:fn:-DTEST_NUMBER=4 --c++26:FAIL: clang/cpp/SemaCXX/warn-bool-conversion.sft.cpp:fn:-DTEST_NUMBER=1 --c++03:FAIL: clang/cpp/SemaCXX/warn-cast-function-type-strict.sft.cpp:fp:-DTEST_NUMBER=1:FAIL: clang/cpp/SemaCXX/warn-cast-function-type.sft.cpp:fp:-DTEST_NUMBER=1:FAIL: @@ -1453,7 +1452,6 @@ clang/cpp/SemaCXX/warn-memsize-comparison.sft.cpp:fn:-DTEST_NUMBER=1:FAIL: clang/cpp/SemaCXX/warn-nrvo.sft.cpp:fp:-DTEST_NUMBER=1:FAIL: clang/cpp/SemaCXX/warn-self-comparisons.sft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL: clang/cpp/SemaCXX/warn-self-comparisons.sft.cpp:fn:-DTEST_NUMBER=2 --c++20:FAIL: -clang/cpp/SemaCXX/warn-self-comparisons.sft.cpp:fn:-DTEST_NUMBER=3 --c++26:FAIL: clang/cpp/SemaCXX/warn-static-const-float.sft.cpp:fn:-DTEST_NUMBER=1 --c++03 -DEXT --c++03 -DNONE --c++03 -DNONE --c++03 -DNONE:FAIL: clang/cpp/SemaCXX/warn-static-const-float.sft.cpp:fn:-DTEST_NUMBER=2 --c++11 -DERR:FAIL: clang/cpp/SemaCXX/warn-static-const-float.sft.cpp:fn:-DTEST_NUMBER=3 --c++11 -DERR:FAIL: diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.8.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.8.1.txt index 28ea3f2c6a..a803af9669 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.8.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.8.1.txt @@ -164,6 +164,26 @@ fe_only -DTEST_NUMBER=8 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers void trex(volatile short left_arm, volatile struct amber right_arm); ^ +"SemaCXX/deprecated.cpp", line 256: warning: comparison between two arrays is deprecated + bool b1 = arr1 == arr2; + ^ + +"SemaCXX/deprecated.cpp", line 258: warning: comparison between two arrays is deprecated + bool b2 = arr1 < arr2; + ^ + +"SemaCXX/deprecated.cpp", line 261: warning: comparison between two arrays is deprecated + bool b3 = arr1 == arr3; + ^ + +"SemaCXX/deprecated.cpp", line 262: warning: comparison between two arrays is deprecated + bool b4 = arr1 < arr3; + ^ + +"SemaCXX/deprecated.cpp", line 268: warning: comparison between two arrays is deprecated + bool b6 = arr1 == f(); + ^ + "SemaCXX/deprecated.cpp", line 280: warning: parameter "x" was set but never used [[deprecated]] void f2([[deprecated]] int x) { ^ diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.9.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.9.1.txt index 5701b8af7f..d834ff0dd9 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.9.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.deprecated.rto/default.9.1.txt @@ -152,6 +152,26 @@ fe_only -DTEST_NUMBER=9 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers void trex(volatile short left_arm, volatile struct amber right_arm); ^ +"SemaCXX/deprecated.cpp", line 256: warning: comparison between two arrays is deprecated + bool b1 = arr1 == arr2; + ^ + +"SemaCXX/deprecated.cpp", line 258: warning: comparison between two arrays is deprecated + bool b2 = arr1 < arr2; + ^ + +"SemaCXX/deprecated.cpp", line 261: warning: comparison between two arrays is deprecated + bool b3 = arr1 == arr3; + ^ + +"SemaCXX/deprecated.cpp", line 262: warning: comparison between two arrays is deprecated + bool b4 = arr1 < arr3; + ^ + +"SemaCXX/deprecated.cpp", line 268: warning: comparison between two arrays is deprecated + bool b6 = arr1 == f(); + ^ + "SemaCXX/deprecated.cpp", line 280: warning: parameter "x" was set but never used [[deprecated]] void f2([[deprecated]] int x) { ^ diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.1.1.txt index 2a201e3e2c..2e0b35c1d4 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.1.1.txt @@ -1,4 +1,16 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c +"Test_name.c", line 21: warning: comparison between two arrays is deprecated + bool h() { return a == b; } // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}} + ^ + +"Test_name.c", line 24: warning: comparison between two arrays is deprecated + return a == c; // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}} + ^ + +"Test_name.c", line 30: warning: comparison between two arrays is deprecated + bool k = NA::x == NB::x; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} + ^ + "Test_name.c", line 53: warning: statement is unreachable return static_field == static_field; // expected-warning {{self-comparison always evaluates to true}} ^ @@ -39,6 +51,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers return s1.array == s1.array; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} ^ +"Test_name.c", line 87: warning: comparison between two arrays is deprecated + return s1.array == s1.array; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} + ^ + "Test_name.c", line 88: warning: statement is unreachable return t.s.static_field == S::static_field; // expected-warning {{self-comparison always evaluates to true}} ^ @@ -103,6 +119,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers return s2.array == s1.array; // FIXME: This always evaluates to false. expected-warning {{deprecated}} ^ +"Test_name.c", line 108: warning: comparison between two arrays is deprecated + return s2.array == s1.array; // FIXME: This always evaluates to false. expected-warning {{deprecated}} + ^ + "Test_name.c", line 109: warning: statement is unreachable return s2.array[0] == s1.array[0]; ^ diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.2.1.txt index af79d46365..a7322bda85 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.self-comparison.rto/default.2.1.txt @@ -1,4 +1,16 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c +"Test_name.c", line 21: warning: comparison between two arrays is deprecated + bool h() { return a == b; } // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}} + ^ + +"Test_name.c", line 24: warning: comparison between two arrays is deprecated + return a == c; // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}} + ^ + +"Test_name.c", line 30: warning: comparison between two arrays is deprecated + bool k = NA::x == NB::x; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} + ^ + "Test_name.c", line 53: warning: statement is unreachable return static_field == static_field; // expected-warning {{self-comparison always evaluates to true}} ^ @@ -39,6 +51,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers return s1.array == s1.array; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} ^ +"Test_name.c", line 87: warning: comparison between two arrays is deprecated + return s1.array == s1.array; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}} + ^ + "Test_name.c", line 88: warning: statement is unreachable return t.s.static_field == S::static_field; // expected-warning {{self-comparison always evaluates to true}} ^ @@ -103,6 +119,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers return s2.array == s1.array; // FIXME: This always evaluates to false. expected-warning {{deprecated}} ^ +"Test_name.c", line 108: warning: comparison between two arrays is deprecated + return s2.array == s1.array; // FIXME: This always evaluates to false. expected-warning {{deprecated}} + ^ + "Test_name.c", line 109: warning: statement is unreachable return s2.array[0] == s1.array[0]; ^ diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.2.1.txt index ffcb555647..8c110d7d4c 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.2.1.txt @@ -1 +1,13 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c +"Test_name.c", line 14: warning: comparison between two arrays is deprecated + if (obj1.str != obj2.str) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 16: warning: comparison between two arrays is deprecated + if (obj1.id != obj2.id) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 23: warning: comparison between two arrays is deprecated + if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.3.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.3.1.txt index 40ce2a691e..ee6e3a200f 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.3.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.3.1.txt @@ -1 +1,13 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c +"Test_name.c", line 14: warning: comparison between two arrays is deprecated + if (obj1.str != obj2.str) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 16: warning: comparison between two arrays is deprecated + if (obj1.id != obj2.id) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 23: warning: comparison between two arrays is deprecated + if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.4.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.4.1.txt index 95ca39fd4f..750fa05fa3 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.4.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.warn-array-comparion.rto/default.4.1.txt @@ -1 +1,14 @@ fe_only -DTEST_NUMBER=4 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++26 Test_name.c +"Test_name.c", line 14: error: comparison between two arrays is not allowed + if (obj1.str != obj2.str) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 16: error: comparison between two arrays is not allowed + if (obj1.id != obj2.id) // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +"Test_name.c", line 23: error: comparison between two arrays is not allowed + if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +3 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.2.1.txt index ffcb555647..2b156b98e4 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.2.1.txt @@ -1 +1,5 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c +"Test_name.c", line 8: warning: comparison between two arrays is deprecated + if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.3.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.3.1.txt index d04c4994d9..f5ca71b80f 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.3.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.warn-self-comparisons.rto/default.3.1.txt @@ -1 +1,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++26 Test_name.c +"Test_name.c", line 8: error: comparison between two arrays is not allowed + if (array1 == array2) { } // not-cxx20-warning {{comparison between two arrays compare their addresses}} cxx20-warning {{comparison between two arrays is deprecated}} + ^ + +1 error detected in the compilation of "Test_name.c". From ee685d10514651a369bb8cfa7a6ec7f722eb7fb2 Mon Sep 17 00:00:00 2001 From: Mohit Mishra Date: Wed, 28 Oct 2026 21:51:52 +0530 Subject: [PATCH 3/3] Also diagnose array comparisons through conversion functions. [GH #370] --- src/expr.c | 27 ++++++++++++++++--- .../gh-370-array-comparisons.txt | 7 +++-- .../tests/changes/.GH370.rto/default.1.1.txt | 14 +++++++++- .../tests/changes/.GH370.rto/default.2.1.txt | 14 +++++++++- .../tests/changes/.GH370.rto/default.3.1.txt | 14 +++++++++- .../changes/.GH370_a.rto/default.1.1.txt | 12 +++++++++ .../changes/.GH370_a.rto/default.2.1.txt | 12 +++++++++ .../changes/.GH370_a.rto/default.3.1.txt | 12 +++++++++ tests/tests/changes/GH370.sft.cpp | 12 +++++++++ tests/tests/changes/GH370_a.sft.cpp | 12 +++++++++ 10 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/expr.c b/src/expr.c index 4394deae12..8750da78fa 100644 --- a/src/expr.c +++ b/src/expr.c @@ -32487,18 +32487,37 @@ different enum types (or, in C, have different affiliated enum types). } /* diagnose_comparison_if_different_enum_types */ +static a_boolean is_array_comparison_operand(an_operand *opnd) +/* +Return TRUE if opnd, an operand of a built-in equality or relational operator, +is an array: either it has array type, or it is a class operand that overload +resolution converted to an array and then to a pointer (e.g., through a +conversion function returning a reference to an array). +*/ +{ + a_boolean is_array = is_array_type(opnd->type); + + if (!is_array && is_expression_operand(opnd)) { + an_expr_node_ptr expr = opnd->variant.expression; + is_array = is_operation_node(expr) && + node_operator_is(expr, eok_array_to_pointer); + } /* if */ + return is_array; +} /* is_array_comparison_operand */ + + static void check_for_array_comparison(an_operand *opnd1, an_operand *opnd2, a_source_position *operator_pos) /* opnd1 and opnd2 are the operands of a built-in equality or relational operator at operator_pos, before the array-to-pointer conversion. If both -have array type, issue a diagnostic: such comparisons are deprecated in C++20 -and not allowed in C++26 (P2865). +are arrays, issue a diagnostic: such comparisons are deprecated in C++20 and +not allowed in C++26 (P2865). */ { - if (cpp20_mode && is_array_type(opnd1->type) && - is_array_type(opnd2->type)) { + if (cpp20_mode && is_array_comparison_operand(opnd1) && + is_array_comparison_operand(opnd2)) { if (cpp26_mode && !gpp_version_is(<150000) && !clangcpp_version_is(<200000)) { /* GCC 15 and Clang 20 implement P2865. Earlier versions only issue a diff --git a/src/pending_changes/gh-370-array-comparisons.txt b/src/pending_changes/gh-370-array-comparisons.txt index 6b7fcc443e..acea6dc869 100644 --- a/src/pending_changes/gh-370-array-comparisons.txt +++ b/src/pending_changes/gh-370-array-comparisons.txt @@ -5,8 +5,11 @@ A comparison between two arrays using an equality or relational operator is deprecated in C++20 and not allowed in C++26 (P2865). The front end did not diagnose it. It is now a warning in C++20 and C++23, and an error in C++26 (only a warning when emulating GCC versions before 15 or Clang versions before -20, which do the same). For example, with --c++26: +20, which do the same). This includes class operands that are converted to +arrays by a conversion function. For example, with --c++26: int a[2], b[2]; - bool x = a == b; // Now an error. + bool x = a == b; // Now an error. bool y = a == &b[0]; // Okay: one operand is a pointer. + struct C { using A = int[2]; operator A &() const; } c; + bool z = c == c; // Now an error. diff --git a/tests/tests/changes/.GH370.rto/default.1.1.txt b/tests/tests/changes/.GH370.rto/default.1.1.txt index 9e70431e0d..1ec9200a82 100644 --- a/tests/tests/changes/.GH370.rto/default.1.1.txt +++ b/tests/tests/changes/.GH370.rto/default.1.1.txt @@ -15,4 +15,16 @@ fe_only -DTEST_NUMBER=1 --c++26 Test_name.c bool x4 = a >= b; ^ -4 errors detected in the compilation of "Test_name.c". +"Test_name.c", line 22: error: comparison between two arrays is not allowed + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 23: error: comparison between two arrays is not allowed + bool z2 = c < c; + ^ + +"Test_name.c", line 24: error: comparison between two arrays is not allowed + bool z3 = c == a; + ^ + +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370.rto/default.2.1.txt b/tests/tests/changes/.GH370.rto/default.2.1.txt index c5c121f800..9c213161a5 100644 --- a/tests/tests/changes/.GH370.rto/default.2.1.txt +++ b/tests/tests/changes/.GH370.rto/default.2.1.txt @@ -15,4 +15,16 @@ fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 150000 Test_name.c bool x4 = a >= b; ^ -4 errors detected in the compilation of "Test_name.c". +"Test_name.c", line 22: error: comparison between two arrays is not allowed + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 23: error: comparison between two arrays is not allowed + bool z2 = c < c; + ^ + +"Test_name.c", line 24: error: comparison between two arrays is not allowed + bool z3 = c == a; + ^ + +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370.rto/default.3.1.txt b/tests/tests/changes/.GH370.rto/default.3.1.txt index 362ad30717..1750fb9a97 100644 --- a/tests/tests/changes/.GH370.rto/default.3.1.txt +++ b/tests/tests/changes/.GH370.rto/default.3.1.txt @@ -15,4 +15,16 @@ fe_only -DTEST_NUMBER=3 --c++26 --clang_version 200000 Test_name.c bool x4 = a >= b; ^ -4 errors detected in the compilation of "Test_name.c". +"Test_name.c", line 22: error: comparison between two arrays is not allowed + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 23: error: comparison between two arrays is not allowed + bool z2 = c < c; + ^ + +"Test_name.c", line 24: error: comparison between two arrays is not allowed + bool z3 = c == a; + ^ + +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/changes/.GH370_a.rto/default.1.1.txt b/tests/tests/changes/.GH370_a.rto/default.1.1.txt index 419dfbbb82..fc6fdc7854 100644 --- a/tests/tests/changes/.GH370_a.rto/default.1.1.txt +++ b/tests/tests/changes/.GH370_a.rto/default.1.1.txt @@ -15,3 +15,15 @@ fe_only -DTEST_NUMBER=1 --c++20 Test_name.c bool x4 = a >= b; ^ +"Test_name.c", line 24: warning: comparison between two arrays is deprecated + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 25: warning: comparison between two arrays is deprecated + bool z2 = c < c; + ^ + +"Test_name.c", line 26: warning: comparison between two arrays is deprecated + bool z3 = c == a; + ^ + diff --git a/tests/tests/changes/.GH370_a.rto/default.2.1.txt b/tests/tests/changes/.GH370_a.rto/default.2.1.txt index e498f3a769..e52bf64bd2 100644 --- a/tests/tests/changes/.GH370_a.rto/default.2.1.txt +++ b/tests/tests/changes/.GH370_a.rto/default.2.1.txt @@ -15,3 +15,15 @@ fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 140000 Test_name.c bool x4 = a >= b; ^ +"Test_name.c", line 24: warning: comparison between two arrays is deprecated + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 25: warning: comparison between two arrays is deprecated + bool z2 = c < c; + ^ + +"Test_name.c", line 26: warning: comparison between two arrays is deprecated + bool z3 = c == a; + ^ + diff --git a/tests/tests/changes/.GH370_a.rto/default.3.1.txt b/tests/tests/changes/.GH370_a.rto/default.3.1.txt index 1879b074b9..de185292e7 100644 --- a/tests/tests/changes/.GH370_a.rto/default.3.1.txt +++ b/tests/tests/changes/.GH370_a.rto/default.3.1.txt @@ -15,3 +15,15 @@ fe_only -DTEST_NUMBER=3 --c++26 --clang_version 190000 Test_name.c bool x4 = a >= b; ^ +"Test_name.c", line 24: warning: comparison between two arrays is deprecated + bool z1 = c == c; // Two arrays: diagnosed. + ^ + +"Test_name.c", line 25: warning: comparison between two arrays is deprecated + bool z2 = c < c; + ^ + +"Test_name.c", line 26: warning: comparison between two arrays is deprecated + bool z3 = c == a; + ^ + diff --git a/tests/tests/changes/GH370.sft.cpp b/tests/tests/changes/GH370.sft.cpp index 5a7750ef79..ed9bfa1d79 100644 --- a/tests/tests/changes/GH370.sft.cpp +++ b/tests/tests/changes/GH370.sft.cpp @@ -14,3 +14,15 @@ bool x4 = a >= b; bool y1 = a == p; // Array and pointer: not diagnosed. bool y2 = p < a; + +// Class operands converted to arrays by conversion functions. +struct C { using arr_t = int[2]; operator arr_t &() const; }; +struct P { operator int *() const; }; +void g(C c, P q) { + bool z1 = c == c; // Two arrays: diagnosed. + bool z2 = c < c; + bool z3 = c == a; + bool z4 = c == p; // Array and pointer: not diagnosed. + bool z5 = q == q; // Conversions to pointers: not diagnosed. + bool z6 = +c == +c; // Explicit decay: not diagnosed. +} diff --git a/tests/tests/changes/GH370_a.sft.cpp b/tests/tests/changes/GH370_a.sft.cpp index 8a8d82148f..7962b19264 100644 --- a/tests/tests/changes/GH370_a.sft.cpp +++ b/tests/tests/changes/GH370_a.sft.cpp @@ -16,3 +16,15 @@ bool x4 = a >= b; bool y1 = a == p; // Array and pointer: not diagnosed. bool y2 = p < a; + +// Class operands converted to arrays by conversion functions. +struct C { using arr_t = int[2]; operator arr_t &() const; }; +struct P { operator int *() const; }; +void g(C c, P q) { + bool z1 = c == c; // Two arrays: diagnosed. + bool z2 = c < c; + bool z3 = c == a; + bool z4 = c == p; // Array and pointer: not diagnosed. + bool z5 = q == q; // Conversions to pointers: not diagnosed. + bool z6 = +c == +c; // Explicit decay: not diagnosed. +}