[clang] [Clang] CWG2749: relational operators involving pointers to void (PR #93046)

Mital Ashok via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 5 04:19:37 PDT 2024


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 <mital at mitalashok.co.uk>
Date: Wed, 22 May 2024 16:01:13 +0100
Subject: [PATCH 1/5] [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 2899bc5ed35ad0..4d9313f4c7ca57 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 a024f9b2a9f8c0..b7aae9395e6357 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 f1aa19e4409e15..d5a47a071e2cd7 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 c160be06dd241c..ae7942aca39e63 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 53ddd566b7dbf9..f0c3c6dbdf97b0 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 at -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 at -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 at -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 e3cd057baba75f..767eee1c74f054 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 9d458330f53768..26f2f60025e8e7 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 <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 21:44:20 +0100
Subject: [PATCH 2/5] 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 f0c3c6dbdf97b0..4c4581c0269ed7 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 at -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 at -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 at -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 at -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

>From 011463a95181bc09efd6bddb3d64361717aaddf3 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital.vaja at googlemail.com>
Date: Thu, 30 May 2024 22:41:13 +0100
Subject: [PATCH 3/5] Update clang/test/CXX/drs/cwg27xx.cpp

Co-authored-by: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
---
 clang/test/CXX/drs/cwg27xx.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index 4c4581c0269ed7..03ae800e1fb985 100644
--- a/clang/test/CXX/drs/cwg27xx.cpp
+++ b/clang/test/CXX/drs/cwg27xx.cpp
@@ -27,7 +27,7 @@ namespace std {
   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 {};

>From 2bedccfbbc587155a5b732d79d72ba9df7843981 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 5 Sep 2024 09:21:19 +0100
Subject: [PATCH 4/5] Clang 19 -> 20

---
 clang/test/CXX/drs/cwg27xx.cpp | 2 +-
 clang/www/cxx_dr_status.html   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index a726f9f8d7a170..1c210cfc583f7d 100644
--- a/clang/test/CXX/drs/cwg27xx.cpp
+++ b/clang/test/CXX/drs/cwg27xx.cpp
@@ -41,7 +41,7 @@ void f(B b) {
 struct D : B {};
 } // namespace cwg2718
 
-namespace cwg2749 { // cwg2749: 19
+namespace cwg2749 { // cwg2749: 20
 
 extern int x[2];
 struct Y {
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index aec188bc1d6591..b638f0ff30bcce 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -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="unreleased" align="center">Clang 19</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>

>From b1549ddc163084ab2f8950fa5c88bddeae7a7a55 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 5 Sep 2024 12:19:21 +0100
Subject: [PATCH 5/5] Fix test failure

---
 clang/test/CXX/drs/cwg27xx.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index 1c210cfc583f7d..b3867696c615b8 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 -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



More information about the cfe-commits mailing list