Hi,

The current compare_three_way implementation makes provision for constant 
evaluation contexts (avoiding reinterpret_cast etc.), but the approach fails 
with Clang; when it compares two const volatile void pointers: "comparison 
between unequal pointers to void has unspecified result". I include a fix and 
test.

Could someone commit the attached patch for me?

Thanks,
Paul


Please consider the environment and think before you print.

The University of the West of Scotland is a registered Scottish charity. 
Charity number SC002520.

This e-mail and any attachment is for authorised use by the intended 
recipient(s) only. It may contain proprietary material, confidential 
information and/or be subject to legal privilege. It should not be copied, 
disclosed to, retained or used by, any other party. If you are not an intended 
recipient then please promptly delete this e-mail and any attachment and all 
copies and inform the sender.

Please note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of the University of the 
West of Scotland.

As a public body, the University of the West of Scotland may be required to 
make available emails as well as other written forms of information as a result 
of a request made under the Freedom of Information (Scotland) Act 2002.
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 07cc83d98f4..638f00716c8 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,10 @@
+2021-08-20  Paul Keir  <paul.k...@uws.ac.uk>
+
+	* libsupc++/compare: Avoid constexpr pointer comparison failure
+	in std::compare_three_way with Clang.
+	* testsuite/18_support/comparisons/pointers/constexpr.cc:
+	New test.
+
 2021-08-19  Jonathan Wakely  <jwak...@redhat.com>
 
 	* doc/xml/manual/status_cxx2020.xml: Move row  earlier in table.
diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare
index 5aee89e3a6e..4081a3f2315 100644
--- a/libstdc++-v3/libsupc++/compare
+++ b/libstdc++-v3/libsupc++/compare
@@ -553,10 +553,10 @@ namespace std
       {
 	if constexpr (__detail::__3way_builtin_ptr_cmp<_Tp, _Up>)
 	  {
+	    if (__builtin_is_constant_evaluated())
+	      return static_cast<_Tp&&>(__t) <=> static_cast<_Up&&>(__u);
 	    auto __pt = static_cast<const volatile void*>(__t);
 	    auto __pu = static_cast<const volatile void*>(__u);
-	    if (__builtin_is_constant_evaluated())
-	      return __pt <=> __pu;
 	    auto __it = reinterpret_cast<__UINTPTR_TYPE__>(__pt);
 	    auto __iu = reinterpret_cast<__UINTPTR_TYPE__>(__pu);
 	    return __it <=> __iu;
diff --git a/libstdc++-v3/testsuite/18_support/comparisons/pointers/constexpr.cc b/libstdc++-v3/testsuite/18_support/comparisons/pointers/constexpr.cc
new file mode 100644
index 00000000000..8e1dc2ed6d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/comparisons/pointers/constexpr.cc
@@ -0,0 +1,43 @@
+// Copyright (C) 2021 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <functional>
+
+constexpr bool check01()
+{
+  int arr[2];
+  bool b1 = &arr[0] < &arr[1];
+  bool b2 = std::less{}(&arr[0], &arr[1]);
+  bool b3 = std::compare_three_way{}(&arr[0],&arr[1]) < 0;
+  return b1 && b2 && b3;
+}
+
+constexpr bool check02()
+{
+  int *p = new int[2];
+  bool b1 = &p[0] < &p[1];
+  bool b2 = std::less{}(&p[0], &p[1]);
+  bool b3 = std::compare_three_way{}(&p[0],&p[1]) < 0;
+  delete [] p;
+  return b1 && b2 && b3;
+}
+
+static_assert(check01());
+static_assert(check02());

Reply via email to