Skip to content

Commit e9ce752

Browse files
[libc++] Remove the constexpr hash<vector<bool>> extension (#132617)
libc++ makes the `hash<vector<bool, A>>::operator()` `constexpr` since C++20, which is a conforming extension, but it was unintended. This patch removes the extension, with an escape hatch macro for it, and the escape hatch will be removed in the future. Test cases for `constexpr` along with the assumption of hash values are moved to the `libcxx/test/libcxx/` subdirectory. --------- Co-authored-by: Louis Dionne <[email protected]>
1 parent a3d2b7e commit e9ce752

File tree

4 files changed

+26
-37
lines changed

4 files changed

+26
-37
lines changed

libcxx/docs/ReleaseNotes/21.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Deprecations and Removals
8080
- The ``_LIBCPP_VERBOSE_ABORT_NOT_NOEXCEPT`` has been removed, making ``std::__libcpp_verbose_abort``
8181
unconditionally ``noexcept``.
8282

83+
- libc++ no longer adds ``constexpr`` to ``std::hash<std::vector<bool, A>>::operator()``, as the ``constexpr`` addition
84+
since C++20 was an unintended extension.
85+
8386
- TODO: The non-conforming extension ``packaged_task::result_type`` has been removed in LLVM 21.
8487

8588
Potentially breaking changes

libcxx/include/__vector/vector_bool.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ class vector<bool, _Allocator> {
512512

513513
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __move_assign_alloc(vector&, false_type) _NOEXCEPT {}
514514

515-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t __hash_code() const _NOEXCEPT;
515+
_LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
516516

517517
friend class __bit_reference<vector>;
518518
friend class __bit_const_reference<vector>;
@@ -1093,7 +1093,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 bool vector<bool, _Allocator>::__invariants() cons
10931093
}
10941094

10951095
template <class _Allocator>
1096-
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_t vector<bool, _Allocator>::__hash_code() const _NOEXCEPT {
1096+
size_t vector<bool, _Allocator>::__hash_code() const _NOEXCEPT {
10971097
size_t __h = 0;
10981098
// do middle whole words
10991099
size_type __n = __size_;
@@ -1110,8 +1110,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t vector<bool, _Allocator>::__hash_code() con
11101110

11111111
template <class _Allocator>
11121112
struct hash<vector<bool, _Allocator> > : public __unary_function<vector<bool, _Allocator>, size_t> {
1113-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_t
1114-
operator()(const vector<bool, _Allocator>& __vec) const _NOEXCEPT {
1113+
_LIBCPP_HIDE_FROM_ABI size_t operator()(const vector<bool, _Allocator>& __vec) const _NOEXCEPT {
11151114
return __vec.__hash_code();
11161115
}
11171116
};

libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,14 @@
1919
#include "test_macros.h"
2020
#include "min_allocator.h"
2121

22-
TEST_CONSTEXPR_CXX20 bool test() {
22+
void test() {
2323
test_hash_enabled<std::vector<bool> >();
2424
test_hash_enabled<std::vector<bool, min_allocator<bool>>>();
25-
26-
return true;
2725
}
2826

2927
int main(int, char**) {
3028
test_library_hash_specializations_available();
3129
test();
32-
#if TEST_STD_VER > 17
33-
static_assert(test());
34-
#endif
3530

3631
return 0;
3732
}

libcxx/test/std/containers/sequences/vector.bool/vector_bool.pass.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
// size_t operator()(T val) const;
1515
// };
1616

17-
// Not very portable
18-
1917
#include <vector>
2018
#include <cassert>
2119
#include <iterator>
@@ -24,35 +22,29 @@
2422
#include "test_macros.h"
2523
#include "min_allocator.h"
2624

27-
TEST_CONSTEXPR_CXX20 bool tests() {
28-
{
29-
typedef std::vector<bool> T;
30-
typedef std::hash<T> H;
25+
template <class VB>
26+
TEST_CONSTEXPR_CXX20 void test() {
27+
typedef std::hash<VB> H;
3128
#if TEST_STD_VER <= 14
32-
static_assert((std::is_same<H::argument_type, T>::value), "");
33-
static_assert((std::is_same<H::result_type, std::size_t>::value), "");
29+
static_assert((std::is_same<typename H::argument_type, VB>::value), "");
30+
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
3431
#endif
35-
ASSERT_NOEXCEPT(H()(T()));
36-
37-
bool ba[] = {true, false, true, true, false};
38-
T vb(std::begin(ba), std::end(ba));
39-
H h;
40-
assert(h(vb) != 0);
32+
ASSERT_NOEXCEPT(H()(VB()));
33+
34+
bool ba[] = {true, false, true, true, false};
35+
VB vb(std::begin(ba), std::end(ba));
36+
H h;
37+
if (!TEST_IS_CONSTANT_EVALUATED) {
38+
const std::size_t hash_value = h(vb);
39+
assert(h(vb) == hash_value);
40+
LIBCPP_ASSERT(hash_value != 0);
4141
}
42+
}
43+
44+
TEST_CONSTEXPR_CXX20 bool tests() {
45+
test<std::vector<bool> >();
4246
#if TEST_STD_VER >= 11
43-
{
44-
typedef std::vector<bool, min_allocator<bool>> T;
45-
typedef std::hash<T> H;
46-
# if TEST_STD_VER <= 14
47-
static_assert((std::is_same<H::argument_type, T>::value), "");
48-
static_assert((std::is_same<H::result_type, std::size_t>::value), "");
49-
# endif
50-
ASSERT_NOEXCEPT(H()(T()));
51-
bool ba[] = {true, false, true, true, false};
52-
T vb(std::begin(ba), std::end(ba));
53-
H h;
54-
assert(h(vb) != 0);
55-
}
47+
test<std::vector<bool, min_allocator<bool>>>();
5648
#endif
5749

5850
return true;

0 commit comments

Comments
 (0)