Skip to content

[Clang] CWG2749: relational operators involving pointers to void #93046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 5, 2024
Merged
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
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ Resolutions to C++ Defect Reports
- Allow ``void{}`` as a prvalue of type ``void``.
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).

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

C Language Changes
------------------

Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
def note_constexpr_typeid_polymorphic : Note<
"typeid applied to expression of polymorphic type %0 is "
"not allowed in a constant expression in C++ standards before C++20">;
def note_constexpr_void_comparison : Note<
"comparison between unequal pointers to void has unspecified result">;
def note_constexpr_temporary_here : Note<"temporary created here">;
def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
def note_constexpr_conditional_never_const : Note<
Expand Down
10 changes: 0 additions & 10 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13895,16 +13895,6 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator();
SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator();

// C++11 [expr.rel]p3:
// Pointers to void (after pointer conversions) can be compared, with a
// result defined as follows: If both pointers represent the same
// address or are both the null pointer value, the result is true if the
// operator is <= or >= and false otherwise; otherwise the result is
// unspecified.
// We interpret this as applying to pointers to *cv* void.
if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational)
Info.CCEDiag(E, diag::note_constexpr_void_comparison);

// C++11 [expr.rel]p2:
// - If two pointers point to non-static data members of the same object,
// or to subobjects or array elements fo such members, recursively, the
Expand Down
8 changes: 2 additions & 6 deletions clang/test/AST/ByteCode/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,8 @@ namespace PointerComparison {
constexpr bool v3 = null == pv; // ok
constexpr bool v4 = qv == pv; // ok

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

Expand Down
46 changes: 45 additions & 1 deletion clang/test/CXX/drs/cwg27xx.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -pedantic-errors -verify=expected,cxx98 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx23 %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx23,since-cxx26 %s

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
// cxx98-error@-1 {{variadic macros are a C99 feature}}
#endif

#if __cplusplus == 199711L
#define __enable_constant_folding(x) (__builtin_constant_p(x) ? (x) : (x))
#else
#define __enable_constant_folding
#endif

namespace std {
#if __cplusplus >= 202002L
struct strong_ordering {
int n;
constexpr operator int() const { return n; }
static const strong_ordering less, equal, greater;
};
constexpr strong_ordering strong_ordering::less{-1},
strong_ordering::equal{0}, strong_ordering::greater{1};
#endif
} // namespace std

namespace cwg2718 { // cwg2718: 2.7
struct B {};
struct D;
Expand All @@ -18,6 +41,27 @@ void f(B b) {
struct D : B {};
} // namespace cwg2718

namespace cwg2749 { // cwg2749: 20

extern int x[2];
struct Y {
int i;
int j;
};
extern Y y[2];

static_assert(__enable_constant_folding(static_cast<void*>(&x[0]) < static_cast<void*>(&x[1])), "");
static_assert(__enable_constant_folding(static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j)), "");
static_assert(__enable_constant_folding(static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i)), "");

#if __cplusplus >= 202002L
static_assert((static_cast<void*>(&x[0]) <=> static_cast<void*>(&x[1])) == std::strong_ordering::less);
static_assert((static_cast<void*>(&y[0].i) <=> static_cast<void*>(&y[0].j)) == std::strong_ordering::less);
static_assert((static_cast<void*>(&y[0].j) <=> static_cast<void*>(&y[1].i)) == std::strong_ordering::less);
#endif

} // namespace cwg2749

namespace cwg2759 { // cwg2759: 19
#if __cplusplus >= 201103L

Expand Down
11 changes: 6 additions & 5 deletions clang/test/CXX/expr/expr.const/p2-0x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,18 +571,19 @@ namespace UnspecifiedRelations {
// [expr.rel]p3: Pointers to void can be compared [...] if both pointers
// represent the same address or are both the null pointer [...]; otherwise
// the result is unspecified.
// Same address restriction removed by CWG2749
struct S { int a, b; } s;
constexpr void *null = 0;
constexpr void *pv = (void*)&s.a;
constexpr void *qv = (void*)&s.b;
constexpr bool v1 = null < (int*)0;
constexpr bool v2 = null < pv; // expected-error {{constant expression}} expected-note {{comparison between 'nullptr' and '&s.a' has unspecified value}}
constexpr bool v3 = null == pv; // ok
constexpr bool v4 = qv == pv; // ok
constexpr bool v5 = qv >= pv; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
constexpr bool v3 = null == pv;
constexpr bool v4 = qv == pv;
constexpr bool v5 = qv >= pv;
constexpr bool v6 = qv > null; // expected-error {{constant expression}} expected-note {{comparison between '&s.b' and 'nullptr' has unspecified value}}
constexpr bool v7 = qv <= (void*)&s.b; // ok
constexpr bool v8 = qv > (void*)&s.a; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
constexpr bool v7 = qv <= (void*)&s.b;
constexpr bool v8 = qv > (void*)&s.a;
}

// - an assignment or a compound assignment (5.17); or
Expand Down
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -16341,7 +16341,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2749.html">2749</a></td>
<td>DRWP</td>
<td>Treatment of "pointer to void" for relational comparisons</td>
<td class="unknown" align="center">Unknown</td>
<td class="unreleased" align="center">Clang 20</td>
</tr>
<tr id="2750">
<td><a href="https://cplusplus.github.io/CWG/issues/2750.html">2750</a></td>
Expand Down
Loading