Skip to content

Commit e117295

Browse files
committed
[Clang] CWG2749: relational operators involving pointers to void
https://cplusplus.github.io/CWG/issues/2749.html This DR's effects are backported to C++98. Does not affect C where integral constant expressions cannot involve pointers.
1 parent 30d484f commit e117295

File tree

7 files changed

+58
-25
lines changed

7 files changed

+58
-25
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ Resolutions to C++ Defect Reports
237237
- P0522 implementation is enabled by default in all language versions, and
238238
provisional wording for CWG2398 is implemented.
239239

240+
- Clang now allows comparing unequal object pointers that have been cast to ``void *``
241+
in constant expressions. These comparisons always worked in non-constant expressions.
242+
(`CWG2749: Treatment of "pointer to void" for relational comparisons <https://cplusplus.github.io/CWG/issues/2749.html>`_).
243+
240244
C Language Changes
241245
------------------
242246

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
148148
def note_constexpr_typeid_polymorphic : Note<
149149
"typeid applied to expression of polymorphic type %0 is "
150150
"not allowed in a constant expression in C++ standards before C++20">;
151-
def note_constexpr_void_comparison : Note<
152-
"comparison between unequal pointers to void has unspecified result">;
153151
def note_constexpr_temporary_here : Note<"temporary created here">;
154152
def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
155153
def note_constexpr_conditional_never_const : Note<

clang/lib/AST/ExprConstant.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13627,16 +13627,6 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
1362713627
SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator();
1362813628
SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator();
1362913629

13630-
// C++11 [expr.rel]p3:
13631-
// Pointers to void (after pointer conversions) can be compared, with a
13632-
// result defined as follows: If both pointers represent the same
13633-
// address or are both the null pointer value, the result is true if the
13634-
// operator is <= or >= and false otherwise; otherwise the result is
13635-
// unspecified.
13636-
// We interpret this as applying to pointers to *cv* void.
13637-
if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational)
13638-
Info.CCEDiag(E, diag::note_constexpr_void_comparison);
13639-
1364013630
// C++11 [expr.rel]p2:
1364113631
// - If two pointers point to non-static data members of the same object,
1364213632
// or to subobjects or array elements fo such members, recursively, the

clang/test/AST/Interp/literals.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,8 @@ namespace PointerComparison {
191191
constexpr bool v3 = null == pv; // ok
192192
constexpr bool v4 = qv == pv; // ok
193193

194-
/// FIXME: These two are rejected by the current interpreter, but
195-
/// accepted by GCC.
196-
constexpr bool v5 = qv >= pv; // ref-error {{constant expression}} \
197-
// ref-note {{unequal pointers to void}}
198-
constexpr bool v8 = qv > (void*)&s.a; // ref-error {{constant expression}} \
199-
// ref-note {{unequal pointers to void}}
194+
constexpr bool v5 = qv >= pv;
195+
constexpr bool v8 = qv > (void*)&s.a;
200196
constexpr bool v6 = qv > null; // both-error {{must be initialized by a constant expression}} \
201197
// both-note {{comparison between '&s.b' and 'nullptr' has unspecified value}}
202198

clang/test/CXX/drs/cwg27xx.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -verify=expected %s
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -Wgnu-folding-constant -verify=expected %s
22
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify=expected %s
33
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -verify=expected %s
44
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -verify=expected %s
55
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -verify=expected %s
66
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -verify=expected,since-cxx23 %s
77
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -verify=expected,since-cxx23,since-cxx26 %s
88

9+
namespace std {
10+
#if __cplusplus >= 202002L
11+
struct strong_ordering {
12+
int n;
13+
constexpr operator int() const { return n; }
14+
static const strong_ordering less, equal, greater;
15+
};
16+
constexpr strong_ordering strong_ordering::less{-1},
17+
strong_ordering::equal{0}, strong_ordering::greater{1};
18+
#endif
19+
}
20+
921
namespace cwg2718 { // cwg2718: 2.7
1022
struct B {};
1123
struct D;
@@ -18,6 +30,38 @@ void f(B b) {
1830
struct D : B {};
1931
} // namespace cwg2718
2032

33+
namespace cwg2749 { // cwg2749: 19
34+
35+
extern int x[2];
36+
struct Y {
37+
int i;
38+
int j;
39+
};
40+
extern Y y[2];
41+
42+
#if __cplusplus >= 201103L
43+
static_assert(static_cast<void*>(x + 0) < static_cast<void*>(x + 1), "");
44+
static_assert(static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j), "");
45+
static_assert(static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i), "");
46+
#else
47+
enum X {
48+
a = static_cast<void*>(x + 0) < static_cast<void*>(x + 1),
49+
// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}}
50+
b = static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j),
51+
// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}}
52+
c = static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i)
53+
// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}}
54+
};
55+
#endif
56+
57+
#if __cplusplus >= 202002L
58+
static_assert((static_cast<void*>(x + 0) <=> static_cast<void*>(x + 1)) == std::strong_ordering::less);
59+
static_assert((static_cast<void*>(&y[0].i) <=> static_cast<void*>(&y[0].j)) == std::strong_ordering::less);
60+
static_assert((static_cast<void*>(&y[0].j) <=> static_cast<void*>(&y[1].i)) == std::strong_ordering::less);
61+
#endif
62+
63+
} // namespace cwg2749
64+
2165
namespace cwg2759 { // cwg2759: 19
2266
#if __cplusplus >= 201103L
2367

clang/test/CXX/expr/expr.const/p2-0x.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,18 +571,19 @@ namespace UnspecifiedRelations {
571571
// [expr.rel]p3: Pointers to void can be compared [...] if both pointers
572572
// represent the same address or are both the null pointer [...]; otherwise
573573
// the result is unspecified.
574+
// Same address restriction removed by CWG2749
574575
struct S { int a, b; } s;
575576
constexpr void *null = 0;
576577
constexpr void *pv = (void*)&s.a;
577578
constexpr void *qv = (void*)&s.b;
578579
constexpr bool v1 = null < (int*)0;
579580
constexpr bool v2 = null < pv; // expected-error {{constant expression}} expected-note {{comparison between 'nullptr' and '&s.a' has unspecified value}}
580-
constexpr bool v3 = null == pv; // ok
581-
constexpr bool v4 = qv == pv; // ok
582-
constexpr bool v5 = qv >= pv; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
581+
constexpr bool v3 = null == pv;
582+
constexpr bool v4 = qv == pv;
583+
constexpr bool v5 = qv >= pv;
583584
constexpr bool v6 = qv > null; // expected-error {{constant expression}} expected-note {{comparison between '&s.b' and 'nullptr' has unspecified value}}
584-
constexpr bool v7 = qv <= (void*)&s.b; // ok
585-
constexpr bool v8 = qv > (void*)&s.a; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
585+
constexpr bool v7 = qv <= (void*)&s.b;
586+
constexpr bool v8 = qv > (void*)&s.a;
586587
}
587588

588589
// - an assignment or a compound assignment (5.17); or

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16302,7 +16302,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1630216302
<td><a href="https://cplusplus.github.io/CWG/issues/2749.html">2749</a></td>
1630316303
<td>DRWP</td>
1630416304
<td>Treatment of "pointer to void" for relational comparisons</td>
16305-
<td class="unknown" align="center">Unknown</td>
16305+
<td class="unreleased" align="center">Clang 19</td>
1630616306
</tr>
1630716307
<tr id="2750">
1630816308
<td><a href="https://cplusplus.github.io/CWG/issues/2750.html">2750</a></td>

0 commit comments

Comments
 (0)