Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/error_msg.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3680,5 +3680,8 @@ 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_bad_gcc_unroll_pragma_value;;"the argument of \"#pragma GCC unroll\" must be a non-negative integral constant less than 65535"
ec_array_comparison_deprecated;;"comparison between two arrays is deprecated"
ec_array_comparison_not_allowed;;"comparison between two arrays is not allowed"
ec_array_comparison_compares_addresses;;"comparison between two arrays compares their addresses"
###############################################################################

58 changes: 58 additions & 0 deletions src/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32487,6 +32487,62 @@ 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), possibly followed by
an implicit qualification conversion.
*/
{
a_boolean is_array = is_array_type(opnd->type);

if (!is_array && is_expression_operand(opnd)) {
an_expr_node_ptr expr = opnd->variant.expression;
/* Skip implicit pointer conversions (e.g., "int *" to "const int *");
a cast written in the source ends the search. */
while (is_cast_operation_node(expr) && expr->compiler_generated &&
is_pointer_type(expr->type)) {
expr = expr->variant.operation.operands;
} /* while */
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
are arrays, issue a diagnostic: such comparisons are deprecated in C++20 and
not allowed in C++26 (P2865). Before C++20, issue a remark (a warning when
emulating Clang 20 or later, which warns by default).
*/
{
if (!C_mode() && is_array_comparison_operand(opnd1) &&
is_array_comparison_operand(opnd2)) {
if (!cpp20_mode) {
expr_pos_diagnostic(clangcpp_version_is(>=200000) ? es_warning
: es_remark,
ec_array_comparison_compares_addresses,
operator_pos);
} else 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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use expr_pos_diagnostic(es_discretionary_error, ...) here.
That way the error severity can be adjusted by the programmer if needed.
(I think Clang and GCC allow that as well.)

} 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,
Expand Down Expand Up @@ -32532,6 +32588,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;
Expand Down Expand Up @@ -33036,6 +33093,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)) {
Expand Down
17 changes: 17 additions & 0 deletions src/pending_changes/gh-370-array-comparisons.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[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). Before C++20 it is a remark (a warning when
emulating Clang 20 or later, which warns by default). 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 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.
2 changes: 0 additions & 2 deletions tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
34 changes: 34 additions & 0 deletions tests/tests/changes/.GH370.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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;
^

"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;
^

"Test_name.c", line 33: error: comparison between two arrays is not allowed
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

8 errors detected in the compilation of "Test_name.c".
34 changes: 34 additions & 0 deletions tests/tests/changes/.GH370.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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;
^

"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;
^

"Test_name.c", line 33: error: comparison between two arrays is not allowed
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

8 errors detected in the compilation of "Test_name.c".
34 changes: 34 additions & 0 deletions tests/tests/changes/.GH370.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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;
^

"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;
^

"Test_name.c", line 33: error: comparison between two arrays is not allowed
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

8 errors detected in the compilation of "Test_name.c".
33 changes: 33 additions & 0 deletions tests/tests/changes/.GH370_a.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c
"Test_name.c", line 13: warning: comparison between two arrays is deprecated
bool x1 = a == b; // Two arrays: diagnosed.
^

"Test_name.c", line 14: warning: comparison between two arrays is deprecated
bool x2 = a != b;
^

"Test_name.c", line 15: warning: comparison between two arrays is deprecated
bool x3 = a < b;
^

"Test_name.c", line 16: warning: comparison between two arrays is deprecated
bool x4 = a >= b;
^

"Test_name.c", line 25: warning: comparison between two arrays is deprecated
bool z1 = c == c; // Two arrays: diagnosed.
^

"Test_name.c", line 26: warning: comparison between two arrays is deprecated
bool z2 = c < c;
^

"Test_name.c", line 27: warning: comparison between two arrays is deprecated
bool z3 = c == a;
^

"Test_name.c", line 36: warning: comparison between two arrays is deprecated
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

33 changes: 33 additions & 0 deletions tests/tests/changes/.GH370_a.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 140000 Test_name.c
"Test_name.c", line 13: warning: comparison between two arrays is deprecated
bool x1 = a == b; // Two arrays: diagnosed.
^

"Test_name.c", line 14: warning: comparison between two arrays is deprecated
bool x2 = a != b;
^

"Test_name.c", line 15: warning: comparison between two arrays is deprecated
bool x3 = a < b;
^

"Test_name.c", line 16: warning: comparison between two arrays is deprecated
bool x4 = a >= b;
^

"Test_name.c", line 25: warning: comparison between two arrays is deprecated
bool z1 = c == c; // Two arrays: diagnosed.
^

"Test_name.c", line 26: warning: comparison between two arrays is deprecated
bool z2 = c < c;
^

"Test_name.c", line 27: warning: comparison between two arrays is deprecated
bool z3 = c == a;
^

"Test_name.c", line 36: warning: comparison between two arrays is deprecated
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

33 changes: 33 additions & 0 deletions tests/tests/changes/.GH370_a.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
fe_only -DTEST_NUMBER=3 --c++26 --clang_version 190000 Test_name.c
"Test_name.c", line 13: warning: comparison between two arrays is deprecated
bool x1 = a == b; // Two arrays: diagnosed.
^

"Test_name.c", line 14: warning: comparison between two arrays is deprecated
bool x2 = a != b;
^

"Test_name.c", line 15: warning: comparison between two arrays is deprecated
bool x3 = a < b;
^

"Test_name.c", line 16: warning: comparison between two arrays is deprecated
bool x4 = a >= b;
^

"Test_name.c", line 25: warning: comparison between two arrays is deprecated
bool z1 = c == c; // Two arrays: diagnosed.
^

"Test_name.c", line 26: warning: comparison between two arrays is deprecated
bool z2 = c < c;
^

"Test_name.c", line 27: warning: comparison between two arrays is deprecated
bool z3 = c == a;
^

"Test_name.c", line 36: warning: comparison between two arrays is deprecated
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

1 change: 1 addition & 0 deletions tests/tests/changes/.GH370_a.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=4 --c++17 Test_name.c
57 changes: 57 additions & 0 deletions tests/tests/changes/.GH370_a.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
fe_only -DTEST_NUMBER=5 --c++17 --remarks Test_name.c
"Test_name.c", line 13: remark: comparison between two arrays compares their addresses
bool x1 = a == b; // Two arrays: diagnosed.
^

"Test_name.c", line 14: remark: comparison between two arrays compares their addresses
bool x2 = a != b;
^

"Test_name.c", line 15: remark: comparison between two arrays compares their addresses
bool x3 = a < b;
^

"Test_name.c", line 16: remark: comparison between two arrays compares their addresses
bool x4 = a >= b;
^

"Test_name.c", line 25: remark: comparison between two arrays compares their addresses
bool z1 = c == c; // Two arrays: diagnosed.
^

"Test_name.c", line 26: remark: comparison between two arrays compares their addresses
bool z2 = c < c;
^

"Test_name.c", line 27: remark: comparison between two arrays compares their addresses
bool z3 = c == a;
^

"Test_name.c", line 25: remark: variable "z1" was declared but never referenced
bool z1 = c == c; // Two arrays: diagnosed.
^

"Test_name.c", line 26: remark: variable "z2" was declared but never referenced
bool z2 = c < c;
^

"Test_name.c", line 27: remark: variable "z3" was declared but never referenced
bool z3 = c == a;
^

"Test_name.c", line 28: remark: variable "z4" was declared but never referenced
bool z4 = c == p; // Array and pointer: not diagnosed.
^

"Test_name.c", line 29: remark: variable "z5" was declared but never referenced
bool z5 = q == q; // Conversions to pointers: not diagnosed.
^

"Test_name.c", line 30: remark: variable "z6" was declared but never referenced
bool z6 = +c == +c; // Explicit decay: not diagnosed.
^

"Test_name.c", line 36: remark: comparison between two arrays compares their addresses
bool h1(C c) { return c == ca; } // Two arrays: diagnosed.
^

Loading
Loading