[libcxx-commits] [libcxx] [libc++] Remove the constexpr `hash<vector<bool>>` extension (PR #132617)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Mar 27 06:38:38 PDT 2025
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/132617
>From 7db09d6e776ee3ed07b9dca5d321391e95c780fb Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 23 Mar 2025 23:31:21 +0800
Subject: [PATCH 1/4] [libc++][test ] Make tests for constexpr `hash`
libcxx-specific
libc++ makes the `hash<vector<bool, A>>::operator()` `constexpr` since
C++20, which is a conforming extension. This patch move the cases to
the `libcxx/test/libcxx/` subdirectory.
---
.../vector.bool/hash.constexpr.pass.cpp | 53 +++++++++++++++++++
.../vector.bool/enabled_hash.pass.cpp | 7 +--
.../vector.bool/vector_bool.pass.cpp | 10 ++--
3 files changed, 60 insertions(+), 10 deletions(-)
create mode 100644 libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
new file mode 100644
index 0000000000000..49874d0504e8a
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// <vector>
+
+// template<class Allocator> struct hash<vector<bool, Allocator>>;
+
+// libc++ makes the operator() of this partial specialization constexpr since C++20, which is a conforming extension.
+
+#include <cassert>
+#include <vector>
+
+#include "min_allocator.h"
+#include "poisoned_hash_helper.h"
+
+constexpr bool test() {
+ {
+ using VB = std::vector<bool>;
+ bool ba[]{true, false, true, true, false};
+ VB vb(std::begin(ba), std::end(ba));
+
+ const std::hash<VB> h{};
+ const auto hash_value = h(vb);
+ assert(hash_value == h(vb));
+ assert(hash_value != 0);
+ }
+ {
+ using VB = std::vector<bool, min_allocator<bool>>;
+ bool ba[] = {true, false, true, true, false};
+ VB vb(std::begin(ba), std::end(ba));
+
+ const std::hash<VB> h{};
+ const auto hash_value = h(vb);
+ assert(hash_value == h(vb));
+ assert(hash_value != 0);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp
index 41cedd68fe50e..cba3101ef5009 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp
@@ -19,19 +19,14 @@
#include "test_macros.h"
#include "min_allocator.h"
-TEST_CONSTEXPR_CXX20 bool test() {
+void test() {
test_hash_enabled<std::vector<bool> >();
test_hash_enabled<std::vector<bool, min_allocator<bool>>>();
-
- return true;
}
int main(int, char**) {
test_library_hash_specializations_available();
test();
-#if TEST_STD_VER > 17
- static_assert(test());
-#endif
return 0;
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/vector_bool.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/vector_bool.pass.cpp
index e270869a8320f..f6bdb7fd5b3ef 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/vector_bool.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/vector_bool.pass.cpp
@@ -14,8 +14,6 @@
// size_t operator()(T val) const;
// };
-// Not very portable
-
#include <vector>
#include <cassert>
#include <iterator>
@@ -37,7 +35,9 @@ TEST_CONSTEXPR_CXX20 bool tests() {
bool ba[] = {true, false, true, true, false};
T vb(std::begin(ba), std::end(ba));
H h;
- assert(h(vb) != 0);
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ assert(h(vb) == h(vb));
+ }
}
#if TEST_STD_VER >= 11
{
@@ -51,7 +51,9 @@ TEST_CONSTEXPR_CXX20 bool tests() {
bool ba[] = {true, false, true, true, false};
T vb(std::begin(ba), std::end(ba));
H h;
- assert(h(vb) != 0);
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ assert(h(vb) == h(vb));
+ }
}
#endif
>From 38d2fe322085340f5391d132d531a81a29a0b146 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 25 Mar 2025 19:32:12 +0800
Subject: [PATCH 2/4] Templatize tests, remove unused inclusion
---
.../vector.bool/hash.constexpr.pass.cpp | 34 +++++++------------
1 file changed, 13 insertions(+), 21 deletions(-)
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
index 49874d0504e8a..7c8d9c2ed91e4 100644
--- a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
@@ -18,29 +18,21 @@
#include <vector>
#include "min_allocator.h"
-#include "poisoned_hash_helper.h"
+
+template <class VBType>
+constexpr void test() {
+ bool ba[]{true, false, true, true, false};
+ VBType vb(std::begin(ba), std::end(ba));
+
+ const std::hash<VBType> h{};
+ const auto hash_value = h(vb);
+ assert(hash_value == h(vb));
+ assert(hash_value != 0);
+}
constexpr bool test() {
- {
- using VB = std::vector<bool>;
- bool ba[]{true, false, true, true, false};
- VB vb(std::begin(ba), std::end(ba));
-
- const std::hash<VB> h{};
- const auto hash_value = h(vb);
- assert(hash_value == h(vb));
- assert(hash_value != 0);
- }
- {
- using VB = std::vector<bool, min_allocator<bool>>;
- bool ba[] = {true, false, true, true, false};
- VB vb(std::begin(ba), std::end(ba));
-
- const std::hash<VB> h{};
- const auto hash_value = h(vb);
- assert(hash_value == h(vb));
- assert(hash_value != 0);
- }
+ test<std::vector<bool>>();
+ test<std::vector<bool, min_allocator<bool>>>();
return true;
}
>From de029f86bc9d38ce0e7e1ce6318ab53c9c9f565d Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 25 Mar 2025 21:18:19 +0800
Subject: [PATCH 3/4] Add transient missing include
---
.../containers/sequences/vector.bool/hash.constexpr.pass.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
index 7c8d9c2ed91e4..f78e270520145 100644
--- a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
@@ -15,6 +15,7 @@
// libc++ makes the operator() of this partial specialization constexpr since C++20, which is a conforming extension.
#include <cassert>
+#include <functional>
#include <vector>
#include "min_allocator.h"
>From 7d9123ad8e4c10c2d89fd35da34570a4c67eb433 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Thu, 27 Mar 2025 21:35:27 +0800
Subject: [PATCH 4/4] Remove extension
---
libcxx/docs/ReleaseNotes/21.rst | 9 ++++++++-
libcxx/include/__vector/vector_bool.h | 15 ++++++++++++---
.../sequences/vector.bool/hash.constexpr.pass.cpp | 5 ++++-
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst
index f67a5fced6fc5..87e52f20949cf 100644
--- a/libcxx/docs/ReleaseNotes/21.rst
+++ b/libcxx/docs/ReleaseNotes/21.rst
@@ -64,13 +64,20 @@ Deprecations and Removals
- ``std::is_pod`` and ``std::is_pod_v`` are deprecated in C++20 and later.
+- libc++ no long adds ``constexpr`` to ``std::hash<std::vector<bool, A>>::operator()``. The ``constexpr`` addition
+ since C++20 was an unintended extension. The ``_LIBCPP_ENABLE_REMOVED_CONSTEXPR_HASH_VECTOR_BOOL`` macro can be
+ defined to temporarily re-enable this extension. This macro will be honored for one release and ignored starting in
+ LLVM 22.
+
Upcoming Deprecations and Removals
----------------------------------
LLVM 22
~~~~~~~
-- TODO
+- TODO: The ``constexpr`` addition to ``std::hash<std::vector<bool, A>>::operator()`` will be removed entirely, and the
+ ``_LIBCPP_ENABLE_REMOVED_CONSTEXPR_HASH_VECTOR_BOOL`` macro that was used to re-enable this extension will be ignored
+ in LLVM 22.
ABI Affecting Changes
diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 569cc5ea898bc..a1b48dcb5f8c7 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -66,6 +66,13 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
+// TODO(LLVM 22): Remove the escape hatch
+#ifdef _LIBCPP_ENABLE_REMOVED_CONSTEXPR_HASH_VECTOR_BOOL
+# define _LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL _LIBCPP_CONSTEXPR_SINCE_CXX20
+#else
+# define _LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL
+#endif
+
template <class _Allocator>
struct hash<vector<bool, _Allocator> >;
@@ -512,7 +519,7 @@ class _LIBCPP_TEMPLATE_VIS vector<bool, _Allocator> {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __move_assign_alloc(vector&, false_type) _NOEXCEPT {}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t __hash_code() const _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL size_t __hash_code() const _NOEXCEPT;
friend class __bit_reference<vector>;
friend class __bit_const_reference<vector>;
@@ -1093,7 +1100,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 bool vector<bool, _Allocator>::__invariants() cons
}
template <class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20 size_t vector<bool, _Allocator>::__hash_code() const _NOEXCEPT {
+_LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL size_t vector<bool, _Allocator>::__hash_code() const _NOEXCEPT {
size_t __h = 0;
// do middle whole words
size_type __n = __size_;
@@ -1111,12 +1118,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t vector<bool, _Allocator>::__hash_code() con
template <class _Allocator>
struct _LIBCPP_TEMPLATE_VIS hash<vector<bool, _Allocator> >
: public __unary_function<vector<bool, _Allocator>, size_t> {
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL size_t
operator()(const vector<bool, _Allocator>& __vec) const _NOEXCEPT {
return __vec.__hash_code();
}
};
+#undef _LIBCPP_CONSTEXPR_HASH_VECTOR_BOOL
+
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
diff --git a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
index f78e270520145..714bca528b9f3 100644
--- a/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector.bool/hash.constexpr.pass.cpp
@@ -8,11 +8,14 @@
// REQUIRES: std-at-least-c++20
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_REMOVED_CONSTEXPR_HASH_VECTOR_BOOL
+
// <vector>
// template<class Allocator> struct hash<vector<bool, Allocator>>;
-// libc++ makes the operator() of this partial specialization constexpr since C++20, which is a conforming extension.
+// Since LLVM 16, libc++ has made the operator() of this partial specialization constexpr since C++20,
+// which is a conforming extension. However, such extension was unintended, and is being removed.
#include <cassert>
#include <functional>
More information about the libcxx-commits
mailing list