https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/93046
>From e1172958f43af7490b5b6e3752a9070265ad17ca Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 22 May 2024 16:01:13 +0100 Subject: [PATCH 1/2] [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. --- clang/docs/ReleaseNotes.rst | 4 ++ .../include/clang/Basic/DiagnosticASTKinds.td | 2 - clang/lib/AST/ExprConstant.cpp | 10 ---- clang/test/AST/Interp/literals.cpp | 8 +--- clang/test/CXX/drs/cwg27xx.cpp | 46 ++++++++++++++++++- clang/test/CXX/expr/expr.const/p2-0x.cpp | 11 +++-- clang/www/cxx_dr_status.html | 2 +- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2899bc5ed35ad..4d9313f4c7ca5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -237,6 +237,10 @@ Resolutions to C++ Defect Reports - P0522 implementation is enabled by default in all language versions, and provisional wording for CWG2398 is implemented. +- 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 ------------------ diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index a024f9b2a9f8c..b7aae9395e635 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -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< diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f1aa19e4409e1..d5a47a071e2cd 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13627,16 +13627,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 diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index c160be06dd241..ae7942aca39e6 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -191,12 +191,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}} diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp index 53ddd566b7dbf..f0c3c6dbdf97b 100644 --- a/clang/test/CXX/drs/cwg27xx.cpp +++ b/clang/test/CXX/drs/cwg27xx.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -verify=expected %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -Wgnu-folding-constant -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -verify=expected %s @@ -6,6 +6,18 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -verify=expected,since-cxx23 %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -verify=expected,since-cxx23,since-cxx26 %s +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 cwg2718 { // cwg2718: 2.7 struct B {}; struct D; @@ -18,6 +30,38 @@ void f(B b) { struct D : B {}; } // namespace cwg2718 +namespace cwg2749 { // cwg2749: 19 + +extern int x[2]; +struct Y { + int i; + int j; +}; +extern Y y[2]; + +#if __cplusplus >= 201103L +static_assert(static_cast<void*>(x + 0) < static_cast<void*>(x + 1), ""); +static_assert(static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j), ""); +static_assert(static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i), ""); +#else +enum X { + a = static_cast<void*>(x + 0) < static_cast<void*>(x + 1), +// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} + b = static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j), +// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} + c = static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i) +// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} +}; +#endif + +#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 diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index e3cd057baba75..767eee1c74f05 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -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 diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 9d458330f5376..26f2f60025e8e 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -16302,7 +16302,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 19</td> </tr> <tr id="2750"> <td><a href="https://cplusplus.github.io/CWG/issues/2750.html">2750</a></td> >From b54f2f90cf295c645d0d2256c0f611e161f960eb Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 21:44:20 +0100 Subject: [PATCH 2/2] Constant fold in C++98 with __builtin_constant_p instead of with enumerator --- clang/test/CXX/drs/cwg27xx.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp index f0c3c6dbdf97b..4c4581c0269ed 100644 --- a/clang/test/CXX/drs/cwg27xx.cpp +++ b/clang/test/CXX/drs/cwg27xx.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -Wgnu-folding-constant -verify=expected %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -verify=expected %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -verify=expected %s @@ -6,6 +6,17 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -verify=expected,since-cxx23 %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -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 { @@ -39,23 +50,12 @@ struct Y { }; extern Y y[2]; -#if __cplusplus >= 201103L -static_assert(static_cast<void*>(x + 0) < static_cast<void*>(x + 1), ""); -static_assert(static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j), ""); -static_assert(static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i), ""); -#else -enum X { - a = static_cast<void*>(x + 0) < static_cast<void*>(x + 1), -// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} - b = static_cast<void*>(&y[0].i) < static_cast<void*>(&y[0].j), -// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} - c = static_cast<void*>(&y[0].j) < static_cast<void*>(&y[1].i) -// expected-warning@-1 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}} -}; -#endif +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*>(&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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits