[libcxx-commits] [libcxx] [libc++] Create a `constexpr` hash to use during constant evaluation (PR #214946)
Vinay Deshmukh via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 13 13:50:24 PDT 2026
https://github.com/vinay-deshmukh updated https://github.com/llvm/llvm-project/pull/214946
>From 817a1a5c598f182cee778de8822cad23a6264568 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 8 Aug 2026 10:33:03 +0100
Subject: [PATCH 01/22] Parameterize first hash test for different hash
function
---
.../unord.hash/integral.pass.cpp | 138 +++++++++---------
1 file changed, 71 insertions(+), 67 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index c798b3aa77ea5..0c09ec5fc9f0e 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -30,17 +30,16 @@
# include "poisoned_hash_helper.h"
#endif
-template <class T>
-void
-test()
-{
+template <class T, template <typename> typename THash = std::hash >
+void test() {
#if TEST_STD_VER >= 11
- test_hash_disabled<const T>();
- test_hash_disabled<volatile T>();
- test_hash_disabled<const volatile T>();
+ test_hash_disabled<const T, THash<const T>>();
+ test_hash_disabled<volatile T, THash<volatile T>>();
+ test_hash_disabled<const volatile T, THash<const volatile T>>();
#endif
- typedef std::hash<T> H;
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -61,70 +60,75 @@ test()
}
}
-int main(int, char**)
-{
- test<bool>();
- test<char>();
- test<signed char>();
- test<unsigned char>();
- test<char16_t>();
- test<char32_t>();
+template <template <typename> typename THash >
+bool test_with_hash() {
+ test<bool, THash>();
+ test<char, THash>();
+ test<signed char, THash>();
+ test<unsigned char, THash>();
+ test<char16_t, THash>();
+ test<char32_t, THash>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t>();
+ test<wchar_t, THash>();
#endif
- test<short>();
- test<unsigned short>();
- test<int>();
- test<unsigned int>();
- test<long>();
- test<unsigned long>();
- test<long long>();
- test<unsigned long long>();
-
-// LWG #2119
- test<std::ptrdiff_t>();
- test<std::size_t>();
-
- test<std::int8_t>();
- test<std::int16_t>();
- test<std::int32_t>();
- test<std::int64_t>();
-
- test<std::int_fast8_t>();
- test<std::int_fast16_t>();
- test<std::int_fast32_t>();
- test<std::int_fast64_t>();
-
- test<std::int_least8_t>();
- test<std::int_least16_t>();
- test<std::int_least32_t>();
- test<std::int_least64_t>();
-
- test<std::intmax_t>();
- test<std::intptr_t>();
-
- test<std::uint8_t>();
- test<std::uint16_t>();
- test<std::uint32_t>();
- test<std::uint64_t>();
-
- test<std::uint_fast8_t>();
- test<std::uint_fast16_t>();
- test<std::uint_fast32_t>();
- test<std::uint_fast64_t>();
-
- test<std::uint_least8_t>();
- test<std::uint_least16_t>();
- test<std::uint_least32_t>();
- test<std::uint_least64_t>();
-
- test<std::uintmax_t>();
- test<std::uintptr_t>();
+ test<short, THash>();
+ test<unsigned short, THash>();
+ test<int, THash>();
+ test<unsigned int, THash>();
+ test<long, THash>();
+ test<unsigned long, THash>();
+ test<long long, THash>();
+ test<unsigned long long, THash>();
+
+ // LWG #2119
+ test<std::ptrdiff_t, THash>();
+ test<std::size_t, THash>();
+
+ test<std::int8_t, THash>();
+ test<std::int16_t, THash>();
+ test<std::int32_t, THash>();
+ test<std::int64_t, THash>();
+
+ test<std::int_fast8_t, THash>();
+ test<std::int_fast16_t, THash>();
+ test<std::int_fast32_t, THash>();
+ test<std::int_fast64_t, THash>();
+
+ test<std::int_least8_t, THash>();
+ test<std::int_least16_t, THash>();
+ test<std::int_least32_t, THash>();
+ test<std::int_least64_t, THash>();
+
+ test<std::intmax_t, THash>();
+ test<std::intptr_t, THash>();
+
+ test<std::uint8_t, THash>();
+ test<std::uint16_t, THash>();
+ test<std::uint32_t, THash>();
+ test<std::uint64_t, THash>();
+
+ test<std::uint_fast8_t, THash>();
+ test<std::uint_fast16_t, THash>();
+ test<std::uint_fast32_t, THash>();
+ test<std::uint_fast64_t, THash>();
+
+ test<std::uint_least8_t, THash>();
+ test<std::uint_least16_t, THash>();
+ test<std::uint_least32_t, THash>();
+ test<std::uint_least64_t, THash>();
+
+ test<std::uintmax_t, THash>();
+ test<std::uintptr_t, THash>();
#ifndef TEST_HAS_NO_INT128
- test<__int128_t>();
- test<__uint128_t>();
+ test<__int128_t, THash>();
+ test<__uint128_t, THash>();
#endif
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
return 0;
}
>From 1b6383a715716d0ba9c787097311e24640433867 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 8 Aug 2026 10:43:07 +0100
Subject: [PATCH 02/22] Setup a failing test for std::__constexpr_hash
---
.../function.objects/unord.hash/integral.pass.cpp | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index 0c09ec5fc9f0e..d4d9bb4fb5041 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -128,7 +128,20 @@ bool test_with_hash() {
return true;
}
+// TODO: move to libcxx/include/__functional/hash.h
+namespace std {
+
+template <class _Key>
+struct __constexpr_hash {};
+
+} // namespace std
+
int main(int, char**) {
assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<std::__constexpr_hash>());
+#endif
+
return 0;
}
>From ce52820da7d6dfe85ff92cfad1b69bcf07fcb33d Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 8 Aug 2026 14:15:15 +0100
Subject: [PATCH 03/22] Pass integer.pass.cpp
---
.../unord.hash/integral.pass.cpp | 50 +++++++++++++++++--
libcxx/test/support/poisoned_hash_helper.h | 2 +-
2 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index d4d9bb4fb5041..7bc1425cb291f 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -31,7 +31,7 @@
#endif
template <class T, template <typename> typename THash = std::hash >
-void test() {
+TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
test_hash_disabled<const T, THash<const T>>();
test_hash_disabled<volatile T, THash<volatile T>>();
@@ -61,7 +61,7 @@ void test() {
}
template <template <typename> typename THash >
-bool test_with_hash() {
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
test<bool, THash>();
test<char, THash>();
test<signed char, THash>();
@@ -128,13 +128,55 @@ bool test_with_hash() {
return true;
}
+#if TEST_STD_VER >= 26
// TODO: move to libcxx/include/__functional/hash.h
namespace std {
-template <class _Key>
-struct __constexpr_hash {};
+// TODO: use _ prefix
+template <typename _Tp>
+concept EnabledForHash = requires(_Tp t) {
+ { std::bool_constant<__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
+};
+
+template <typename _Tp>
+concept DisabledForHash = not EnabledForHash<_Tp>;
+
+// TODO: document the constraints of using this at runtime OR make it consteval only
+template <typename _Tp>
+struct __constexpr_hash;
+
+template <DisabledForHash _Tp>
+struct __constexpr_hash<_Tp> {
+ __constexpr_hash() = delete;
+ __constexpr_hash(const __constexpr_hash&) = delete;
+ __constexpr_hash& operator=(const __constexpr_hash&) = delete;
+};
+
+template <EnabledForHash _Tp>
+struct __constexpr_hash<_Tp> {
+ [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __v) const noexcept {
+ if constexpr (std::is_same_v<_Tp, nullptr_t>) {
+ return 662607004ull;
+ } else if constexpr (std::is_integral_v<_Tp>) {
+ if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
+ return static_cast<size_t>(__v);
+ } else {
+ constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
+ char region[multiple];
+
+ // TODO: 0, 1, 2, 3, 4
+ return region[multiple - 1]; // TODO: hash-ing
+ }
+ }
+ __builtin_unreachable(); // todo: revisit
+ }
+
+ __constexpr_hash() noexcept = default;
+ __constexpr_hash& operator=(const __constexpr_hash&) = default;
+};
} // namespace std
+#endif
int main(int, char**) {
assert(test_with_hash<std::hash>());
diff --git a/libcxx/test/support/poisoned_hash_helper.h b/libcxx/test/support/poisoned_hash_helper.h
index cd71cd70d6a84..ec3f6e9af813f 100644
--- a/libcxx/test/support/poisoned_hash_helper.h
+++ b/libcxx/test/support/poisoned_hash_helper.h
@@ -87,7 +87,7 @@ TEST_CONSTEXPR_CXX20 void test_hash_enabled(Key const& key = Key{}) {
// Test that the specified Hash meets the requirements of a disabled hash.
template <class Key, class Hash = std::hash<Key>>
-void test_hash_disabled() {
+TEST_CONSTEXPR_CXX26 void test_hash_disabled() {
// Disabled hash requirements
static_assert(!std::is_default_constructible<Hash>::value, "");
static_assert(!std::is_copy_constructible<Hash>::value, "");
>From ae2da4414f761421c0eee17cd97cbeae03ee6c2b Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Mon, 10 Aug 2026 08:43:19 +0100
Subject: [PATCH 04/22] -Wc++17 extensions
---
.../std/utilities/function.objects/unord.hash/integral.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index 7bc1425cb291f..4974916ed4c80 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -30,7 +30,7 @@
# include "poisoned_hash_helper.h"
#endif
-template <class T, template <typename> typename THash = std::hash >
+template <class T, template <class> class THash = std::hash >
TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
test_hash_disabled<const T, THash<const T>>();
>From 190e96559aecedd698d270d0778508bbc0e83323 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 23 Aug 2026 18:03:46 +0100
Subject: [PATCH 05/22] Move to test header
---
.../unord.hash/integral.pass.cpp | 53 +----------------
libcxx/test/support/constexpr_hash.h | 57 +++++++++++++++++++
2 files changed, 59 insertions(+), 51 deletions(-)
create mode 100644 libcxx/test/support/constexpr_hash.h
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index 4974916ed4c80..f2c217f10db96 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -24,6 +24,7 @@
#include <limits>
#include <type_traits>
+#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
@@ -128,61 +129,11 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
return true;
}
-#if TEST_STD_VER >= 26
-// TODO: move to libcxx/include/__functional/hash.h
-namespace std {
-
-// TODO: use _ prefix
-template <typename _Tp>
-concept EnabledForHash = requires(_Tp t) {
- { std::bool_constant<__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
-};
-
-template <typename _Tp>
-concept DisabledForHash = not EnabledForHash<_Tp>;
-
-// TODO: document the constraints of using this at runtime OR make it consteval only
-template <typename _Tp>
-struct __constexpr_hash;
-
-template <DisabledForHash _Tp>
-struct __constexpr_hash<_Tp> {
- __constexpr_hash() = delete;
- __constexpr_hash(const __constexpr_hash&) = delete;
- __constexpr_hash& operator=(const __constexpr_hash&) = delete;
-};
-
-template <EnabledForHash _Tp>
-struct __constexpr_hash<_Tp> {
- [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __v) const noexcept {
- if constexpr (std::is_same_v<_Tp, nullptr_t>) {
- return 662607004ull;
- } else if constexpr (std::is_integral_v<_Tp>) {
- if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
- return static_cast<size_t>(__v);
- } else {
- constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
- char region[multiple];
-
- // TODO: 0, 1, 2, 3, 4
- return region[multiple - 1]; // TODO: hash-ing
- }
- }
- __builtin_unreachable(); // todo: revisit
- }
-
- __constexpr_hash() noexcept = default;
- __constexpr_hash& operator=(const __constexpr_hash&) = default;
-};
-
-} // namespace std
-#endif
-
int main(int, char**) {
assert(test_with_hash<std::hash>());
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<std::__constexpr_hash>());
+ static_assert(test_with_hash<support::constexpr_hash>());
#endif
return 0;
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
new file mode 100644
index 0000000000000..b7881f0c73df9
--- /dev/null
+++ b/libcxx/test/support/constexpr_hash.h
@@ -0,0 +1,57 @@
+
+
+#include <__type_traits/is_unqualified.h>
+
+#include "test_macros.h"
+#include <type_traits>
+
+namespace support {
+
+#if TEST_STD_VER >= 26
+
+// TODO: use _ prefix
+template <typename _Tp>
+concept EnabledForHash = requires(_Tp t) {
+ { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
+};
+
+template <typename _Tp>
+concept DisabledForHash = not EnabledForHash<_Tp>;
+
+// TODO: document the constraints of using this at runtime OR make it consteval only
+template <typename _Tp>
+struct constexpr_hash;
+
+template <DisabledForHash _Tp>
+struct constexpr_hash<_Tp> {
+ constexpr_hash() = delete;
+ constexpr_hash(const constexpr_hash&) = delete;
+ constexpr_hash& operator=(const constexpr_hash&) = delete;
+};
+
+template <EnabledForHash _Tp>
+struct constexpr_hash<_Tp> {
+ [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __v) const noexcept {
+ if constexpr (std::is_same_v<_Tp, nullptr_t>) {
+ return 662607004ull;
+ } else if constexpr (std::is_integral_v<_Tp>) {
+ if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
+ return static_cast<size_t>(__v);
+ } else {
+ constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
+ char region[multiple];
+
+ // TODO: 0, 1, 2, 3, 4
+ return region[multiple - 1]; // TODO: hash-ing
+ }
+ }
+ __builtin_unreachable(); // todo: revisit
+ }
+
+ constexpr_hash() noexcept = default;
+ constexpr_hash& operator=(const constexpr_hash&) = default;
+};
+
+} // namespace support
+
+#endif
>From ae90cb4d7dbfd421d9af691293c35f596bad828b Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 23 Aug 2026 18:31:40 +0100
Subject: [PATCH 06/22] floating.pass.cpp
---
.../unord.hash/floating.pass.cpp | 32 ++++++++++++-------
libcxx/test/support/constexpr_hash.h | 20 ++++++++++++
2 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
index f6c31d068b231..c377aab5e869d 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
@@ -25,23 +25,23 @@
#include <limits>
#include <cmath>
+#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
# include "poisoned_hash_helper.h"
#endif
-template <class T>
-void
-test()
-{
+template <class T, template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
- test_hash_disabled<const T>();
- test_hash_disabled<volatile T>();
- test_hash_disabled<const volatile T>();
+ test_hash_disabled<const T, THash<const T>>();
+ test_hash_disabled<volatile T, THash<volatile T>>();
+ test_hash_disabled<const volatile T, THash<const volatile T>>();
#endif
- typedef std::hash<T> H;
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -78,11 +78,19 @@ test()
assert(pinf != ninf);
}
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test<float, THash>();
+ test<double, THash>();
+ test<long double, THash>();
+ return true;
+}
+
int main(int, char**)
{
- test<float>();
- test<double>();
- test<long double>();
-
+ assert(test_with_hash<std::hash>());
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
return 0;
}
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index b7881f0c73df9..e298500f60ad5 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -4,6 +4,7 @@
#include "test_macros.h"
#include <type_traits>
+#include <bit>
namespace support {
@@ -44,6 +45,25 @@ struct constexpr_hash<_Tp> {
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
+ } else if constexpr (std::is_floating_point_v<_Tp>) {
+ if (__v == 0.0f)
+ return 0;
+ // return __scalar_hash<_Tp>::operator()(__v);
+
+ constexpr size_t multiple = sizeof(_Tp) / sizeof(char);
+ std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(__v);
+
+ // TODO: pack indexing?
+ size_t res = 0;
+ for(size_t i = 0; i < multiple; ++i) {
+ res ^= region[i];
+ }
+ return res;
+
+ // TODO: 0, 1, 2, 3, 4
+ // return region[multiple - 1]; // TODO: hash-ing
+ // return 1234ULL;
+
}
__builtin_unreachable(); // todo: revisit
}
>From 69d7d90dfa9e9690218e7efbb9b24a846fe056cf Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Mon, 24 Aug 2026 08:31:18 +0100
Subject: [PATCH 07/22] disable pointer types explicitly
---
.../unord.hash/pointer.pass.cpp | 30 +++++++++++++------
libcxx/test/support/constexpr_hash.h | 25 +++++++++++++---
2 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
index 784831018a006..c6c2a6e805f2b 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
@@ -24,13 +24,13 @@
#include <functional>
#include <type_traits>
+#include "constexpr_hash.h"
#include "test_macros.h"
-template <class T>
-void
-test()
-{
- typedef std::hash<T> H;
+template <class T, template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test() {
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -44,9 +44,11 @@ test()
assert(h(&i) != h(&j));
}
-void test_nullptr() {
+template < template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test_nullptr() {
typedef std::nullptr_t T;
- typedef std::hash<T> H;
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -54,10 +56,20 @@ void test_nullptr() {
ASSERT_NOEXCEPT(H()(T()));
}
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test_nullptr< THash>();
+ return true;
+}
+
int main(int, char**)
{
- test<int*>();
- test_nullptr();
+ assert(test_with_hash<std::hash>());
+ test<int*>();
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
return 0;
}
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index e298500f60ad5..0debee277ed0a 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -14,10 +14,26 @@ namespace support {
template <typename _Tp>
concept EnabledForHash = requires(_Tp t) {
{ std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
-};
+}
+
+// we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
+// note: bit_cast from a pointer type is not allowed in a constant expression
+// read of member '__a' of union with active member '__t' is not allowed in a constant expression
+/*
+
+ union {
+ _Tp __t;
+ size_t __a;
+ } __u;
+ __u.__a = 0;
+ __u.__t = __v;
+ return __u.__a;
+*/
+and not std::is_pointer_v<_Tp>;
+
template <typename _Tp>
-concept DisabledForHash = not EnabledForHash<_Tp>;
+concept DisabledForHash = not EnabledForHash<_Tp> ;
// TODO: document the constraints of using this at runtime OR make it consteval only
template <typename _Tp>
@@ -45,8 +61,9 @@ struct constexpr_hash<_Tp> {
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
- } else if constexpr (std::is_floating_point_v<_Tp>) {
+ } else if constexpr (std::is_floating_point_v<_Tp> ) {
if (__v == 0.0f)
+
return 0;
// return __scalar_hash<_Tp>::operator()(__v);
@@ -64,7 +81,7 @@ struct constexpr_hash<_Tp> {
// return region[multiple - 1]; // TODO: hash-ing
// return 1234ULL;
- }
+ }
__builtin_unreachable(); // todo: revisit
}
>From e6378f30fff8c24a6233e7fde3d5dcf83ab1999d Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Mon, 24 Aug 2026 08:48:13 +0100
Subject: [PATCH 08/22] enum.pass.cpp
---
.../function.objects/unord.hash/enum.pass.cpp | 39 +++++++-----
libcxx/test/support/constexpr_hash.h | 60 ++++++++++---------
2 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
index 05a19329f909a..cdc982f12c638 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
@@ -19,6 +19,7 @@
#include <limits>
#include <type_traits>
+#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
@@ -33,17 +34,16 @@ enum class EightBitColors : std::uint8_t { red, orange, yellow, green, blue, ind
enum Fruits { apple, pear, grape, mango, cantaloupe };
-template <class T>
-void
-test()
-{
+template <class T, template <class> typename THash>
+TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
test_hash_disabled<const T>();
test_hash_disabled<volatile T>();
test_hash_disabled<const volatile T>();
#endif
- typedef std::hash<T> H;
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -52,7 +52,8 @@ test()
typedef typename std::underlying_type<T>::type under_type;
H h1;
- std::hash<under_type> h2;
+ // std::hash<under_type> h2;
+ THash<under_type> h2;
for (int i = 0; i <= 5; ++i)
{
T t(static_cast<T> (i));
@@ -62,16 +63,26 @@ test()
}
}
-int main(int, char**)
-{
- test<Cardinals>();
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test<Cardinals, THash>();
- test<Colors>();
- test<ShortColors>();
- test<LongColors>();
- test<EightBitColors>();
+ test<Colors, THash>();
+ test<ShortColors, THash>();
+ test<LongColors, THash>();
+ test<EightBitColors, THash>();
- test<Fruits>();
+ test<Fruits, THash>();
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
return 0;
}
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 0debee277ed0a..8c79b15db87d6 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -1,6 +1,7 @@
#include <__type_traits/is_unqualified.h>
+#include <__type_traits/underlying_type.h>
#include "test_macros.h"
#include <type_traits>
@@ -12,14 +13,15 @@ namespace support {
// TODO: use _ prefix
template <typename _Tp>
-concept EnabledForHash = requires(_Tp t) {
- { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
-}
+concept EnabledForHash =
+ requires(_Tp t) {
+ { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
+ }
-// we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
-// note: bit_cast from a pointer type is not allowed in a constant expression
-// read of member '__a' of union with active member '__t' is not allowed in a constant expression
-/*
+ // we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
+ // note: bit_cast from a pointer type is not allowed in a constant expression
+ // read of member '__a' of union with active member '__t' is not allowed in a constant expression
+ /*
union {
_Tp __t;
@@ -29,11 +31,10 @@ concept EnabledForHash = requires(_Tp t) {
__u.__t = __v;
return __u.__a;
*/
-and not std::is_pointer_v<_Tp>;
-
+ and not std::is_pointer_v<_Tp>;
template <typename _Tp>
-concept DisabledForHash = not EnabledForHash<_Tp> ;
+concept DisabledForHash = not EnabledForHash<_Tp>;
// TODO: document the constraints of using this at runtime OR make it consteval only
template <typename _Tp>
@@ -41,7 +42,7 @@ struct constexpr_hash;
template <DisabledForHash _Tp>
struct constexpr_hash<_Tp> {
- constexpr_hash() = delete;
+ constexpr_hash() = delete;
constexpr_hash(const constexpr_hash&) = delete;
constexpr_hash& operator=(const constexpr_hash&) = delete;
};
@@ -61,31 +62,34 @@ struct constexpr_hash<_Tp> {
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
- } else if constexpr (std::is_floating_point_v<_Tp> ) {
- if (__v == 0.0f)
+ } else if constexpr (std::is_floating_point_v<_Tp>) {
+ if (__v == 0.0f)
- return 0;
- // return __scalar_hash<_Tp>::operator()(__v);
+ return 0;
+ // return __scalar_hash<_Tp>::operator()(__v);
- constexpr size_t multiple = sizeof(_Tp) / sizeof(char);
- std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(__v);
+ constexpr size_t multiple = sizeof(_Tp) / sizeof(char);
+ std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(__v);
- // TODO: pack indexing?
- size_t res = 0;
- for(size_t i = 0; i < multiple; ++i) {
- res ^= region[i];
- }
- return res;
+ // TODO: pack indexing?
+ size_t res = 0;
+ for (size_t i = 0; i < multiple; ++i) {
+ res ^= region[i];
+ }
+ return res;
- // TODO: 0, 1, 2, 3, 4
- // return region[multiple - 1]; // TODO: hash-ing
- // return 1234ULL;
+ // TODO: 0, 1, 2, 3, 4
+ // return region[multiple - 1]; // TODO: hash-ing
+ // return 1234ULL;
- }
+ } else if constexpr (std::is_enum_v<_Tp>) {
+ using type = std::__underlying_type_t<_Tp>;
+ return constexpr_hash<type>()(static_cast<type>(__v));
+ }
__builtin_unreachable(); // todo: revisit
}
- constexpr_hash() noexcept = default;
+ constexpr_hash() noexcept = default;
constexpr_hash& operator=(const constexpr_hash&) = default;
};
>From 89fc017527db8466fdf95f8983ee5bb2760a9e5d Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Wed, 26 Aug 2026 08:54:26 +0100
Subject: [PATCH 09/22] non_enum passes
---
.../unord.hash/non_enum.pass.cpp | 30 ++++++---
libcxx/test/support/constexpr_hash.h | 62 +++++++++----------
2 files changed, 53 insertions(+), 39 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
index 94cc9d912f3a7..8632e907f1caf 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
@@ -18,22 +18,36 @@
#include <cassert>
#include <type_traits>
+#include "constexpr_hash.h"
#include "test_macros.h"
struct X {};
-int main(int, char**)
-{
- using H = std::hash<X>;
- static_assert(!std::is_default_constructible<H>::value, "");
- static_assert(!std::is_copy_constructible<H>::value, "");
- static_assert(!std::is_move_constructible<H>::value, "");
- static_assert(!std::is_copy_assignable<H>::value, "");
- static_assert(!std::is_move_assignable<H>::value, "");
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ using H = THash<X>;
+
+ static_assert(!std::is_default_constructible<H>::value, "");
+ static_assert(!std::is_copy_constructible<H>::value, "");
+ static_assert(!std::is_move_constructible<H>::value, "");
+ static_assert(!std::is_copy_assignable<H>::value, "");
+ static_assert(!std::is_move_assignable<H>::value, "");
#if TEST_STD_VER > 14
static_assert(!std::is_invocable<H, X&>::value, "");
static_assert(!std::is_invocable<H, X const&>::value, "");
#endif
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+ // using H = std::hash<X>;
+ // using H = support::constexpr_hash<X>;
+
return 0;
}
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 8c79b15db87d6..9281384e1f30b 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -11,48 +11,41 @@ namespace support {
#if TEST_STD_VER >= 26
-// TODO: use _ prefix
-template <typename _Tp>
-concept EnabledForHash =
- requires(_Tp t) {
- { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
- }
-
- // we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
- // note: bit_cast from a pointer type is not allowed in a constant expression
- // read of member '__a' of union with active member '__t' is not allowed in a constant expression
- /*
-
- union {
- _Tp __t;
- size_t __a;
- } __u;
- __u.__a = 0;
- __u.__t = __v;
- return __u.__a;
-*/
- and not std::is_pointer_v<_Tp>;
-
-template <typename _Tp>
-concept DisabledForHash = not EnabledForHash<_Tp>;
-
// TODO: document the constraints of using this at runtime OR make it consteval only
template <typename _Tp>
struct constexpr_hash;
-template <DisabledForHash _Tp>
-struct constexpr_hash<_Tp> {
+// we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
+template <class _Tp>
+struct constexpr_hash<_Tp*> {
constexpr_hash() = delete;
constexpr_hash(const constexpr_hash&) = delete;
constexpr_hash& operator=(const constexpr_hash&) = delete;
};
-template <EnabledForHash _Tp>
+template <>
+struct constexpr_hash<std::nullptr_t> {
+ constexpr_hash() noexcept = default;
+ constexpr_hash& operator=(const constexpr_hash&) = default;
+
+ [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(std::nullptr_t) const noexcept {
+ return 662607004ull;
+ }
+};
+
+template <typename _Tp>
+ requires requires(_Tp t) {
+ { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
+
+ {
+ std::bool_constant< std::bool_constant<std::is_integral_v<_Tp>>() ||
+ std::bool_constant<std::is_floating_point_v<_Tp>>() ||
+ std::bool_constant<std::is_enum_v<_Tp>>() >()
+ } -> std::same_as<std::true_type>;
+ }
struct constexpr_hash<_Tp> {
[[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __v) const noexcept {
- if constexpr (std::is_same_v<_Tp, nullptr_t>) {
- return 662607004ull;
- } else if constexpr (std::is_integral_v<_Tp>) {
+ if constexpr (std::is_integral_v<_Tp>) {
if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
return static_cast<size_t>(__v);
} else {
@@ -93,6 +86,13 @@ struct constexpr_hash<_Tp> {
constexpr_hash& operator=(const constexpr_hash&) = default;
};
+template <class _Tp>
+struct constexpr_hash {
+ constexpr_hash() = delete;
+ constexpr_hash(const constexpr_hash&) = delete;
+ constexpr_hash& operator=(const constexpr_hash&) = delete;
+};
+
} // namespace support
#endif
>From df2ad7abc83d6f4fbfc82b4f16a4fd924034d61d Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Fri, 28 Aug 2026 09:08:45 +0100
Subject: [PATCH 10/22] enabled_hashes.pass.cpp
---
.../unord.hash/enabled_hashes.pass.cpp | 5 ++++
libcxx/test/support/constexpr_hash.h | 8 +++--
libcxx/test/support/poisoned_hash_helper.h | 30 +++++++++++++++++--
3 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
index 53d8ed788d866..43afca3407174 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
@@ -18,9 +18,14 @@
#include "poisoned_hash_helper.h"
#include "test_macros.h"
+#include "constexpr_hash.h"
int main(int, char**) {
test_library_hash_specializations_available();
+#if TEST_STD_VER >= 26
+ static_assert(test_constexpr_hash_specializations_available());
+#endif
+
return 0;
}
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 9281384e1f30b..b3278ea28c382 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -1,4 +1,6 @@
+#ifndef SUPPORT_CONSTEXPR_HASH_H
+#define SUPPORT_CONSTEXPR_HASH_H
#include <__type_traits/is_unqualified.h>
#include <__type_traits/underlying_type.h>
@@ -49,8 +51,8 @@ struct constexpr_hash<_Tp> {
if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
return static_cast<size_t>(__v);
} else {
- constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
- char region[multiple];
+ constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
+ std::array<size_t, multiple> region = std::bit_cast<std::array<size_t, multiple>>(__v);
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
@@ -96,3 +98,5 @@ struct constexpr_hash {
} // namespace support
#endif
+
+#endif // SUPPORT_CONSTEXPR_HASH_H
\ No newline at end of file
diff --git a/libcxx/test/support/poisoned_hash_helper.h b/libcxx/test/support/poisoned_hash_helper.h
index ec3f6e9af813f..e1cc82244200e 100644
--- a/libcxx/test/support/poisoned_hash_helper.h
+++ b/libcxx/test/support/poisoned_hash_helper.h
@@ -16,6 +16,7 @@
#include <type_traits>
#include <utility>
+#include "constexpr_hash.h"
#include "test_macros.h"
#include "type_algorithms.h"
@@ -128,9 +129,9 @@ using LibraryHashTypes =
types::type_list<Enum, EnumClass, void*, void const*, Class*, std::nullptr_t>>;
struct TestHashEnabled {
- template <class T>
+ template <class Key>
void operator()() const {
- test_hash_enabled<T>();
+ test_hash_enabled<Key>();
}
};
@@ -141,4 +142,29 @@ void test_library_hash_specializations_available() {
types::for_each(Types(), TestHashEnabled());
}
+#if TEST_STD_VER >= 26
+
+struct TestConstexprHashEnabled {
+ template <class Key>
+ constexpr void operator()() const {
+ test_hash_enabled<Key, support::constexpr_hash<Key>>();
+ }
+};
+
+// We use the same types that std::hash uses, except for pointers since pointers can't be hashed during constant evaluation
+using SupportedConstexprHashTypes =
+ types::concatenate_t<types::arithmetic_types,
+ types::type_list<Enum,
+ EnumClass, //void*, void const*, Class*,
+ std::nullptr_t>>;
+
+// Test that each of the library hash specializations for arithmetic types,
+// enum types, and pointer types are available and enabled.
+template <class Types = SupportedConstexprHashTypes>
+constexpr bool test_constexpr_hash_specializations_available() {
+ types::for_each(Types(), TestConstexprHashEnabled());
+ return true;
+}
+#endif
+
#endif // SUPPORT_POISONED_HASH_HELPER_H
>From 0dac4df85918d1419287683ea87fe2cad6163f30 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 10 Oct 2026 12:02:16 +0100
Subject: [PATCH 11/22] header, remove doc, NL
---
libcxx/test/support/constexpr_hash.h | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index b3278ea28c382..d9b57cb429662 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -1,3 +1,14 @@
+//===- constexpr_hash.h - Classes for representing statements -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a constexpr `hash`
+//
+//===----------------------------------------------------------------------===//
#ifndef SUPPORT_CONSTEXPR_HASH_H
#define SUPPORT_CONSTEXPR_HASH_H
@@ -13,7 +24,6 @@ namespace support {
#if TEST_STD_VER >= 26
-// TODO: document the constraints of using this at runtime OR make it consteval only
template <typename _Tp>
struct constexpr_hash;
@@ -99,4 +109,4 @@ struct constexpr_hash {
#endif
-#endif // SUPPORT_CONSTEXPR_HASH_H
\ No newline at end of file
+#endif // SUPPORT_CONSTEXPR_HASH_H
>From 2551725347d4b740c420fec2d4f3bb56397fc57d Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 10 Oct 2026 12:18:13 +0100
Subject: [PATCH 12/22] use std::to_underlying over __underlying_type_t
---
libcxx/test/support/constexpr_hash.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index d9b57cb429662..b42a7d9027ef3 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -14,7 +14,7 @@
#define SUPPORT_CONSTEXPR_HASH_H
#include <__type_traits/is_unqualified.h>
-#include <__type_traits/underlying_type.h>
+#include <utility>
#include "test_macros.h"
#include <type_traits>
@@ -88,7 +88,7 @@ struct constexpr_hash<_Tp> {
// return 1234ULL;
} else if constexpr (std::is_enum_v<_Tp>) {
- using type = std::__underlying_type_t<_Tp>;
+ using type = decltype(std::to_underlying(std::declval<_Tp>()));
return constexpr_hash<type>()(static_cast<type>(__v));
}
__builtin_unreachable(); // todo: revisit
>From 4b6040300397bb5cf4cdb6bc8efc49d62444dc44 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sat, 10 Oct 2026 12:22:51 +0100
Subject: [PATCH 13/22] use <cstddef>
---
libcxx/test/support/constexpr_hash.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index b42a7d9027ef3..4f0c9569dfb77 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -19,6 +19,7 @@
#include "test_macros.h"
#include <type_traits>
#include <bit>
+#include <cstddef>
namespace support {
>From 80988eaa151e43ae1bdce76475528d9a48aad937 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 11 Oct 2026 13:06:04 +0100
Subject: [PATCH 14/22] Avoid __ugly names
---
libcxx/test/support/constexpr_hash.h | 40 ++++++++++++++--------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 4f0c9569dfb77..f1824de405a67 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -25,12 +25,12 @@ namespace support {
#if TEST_STD_VER >= 26
-template <typename _Tp>
+template <typename Key>
struct constexpr_hash;
// we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
-template <class _Tp>
-struct constexpr_hash<_Tp*> {
+template <class Key>
+struct constexpr_hash<Key*> {
constexpr_hash() = delete;
constexpr_hash(const constexpr_hash&) = delete;
constexpr_hash& operator=(const constexpr_hash&) = delete;
@@ -46,35 +46,35 @@ struct constexpr_hash<std::nullptr_t> {
}
};
-template <typename _Tp>
- requires requires(_Tp t) {
- { std::bool_constant<std::__is_unqualified_v<_Tp>>() } -> std::same_as<std::true_type>;
+template <typename Key>
+ requires requires(Key t) {
+ { std::bool_constant<std::__is_unqualified_v<Key>>() } -> std::same_as<std::true_type>;
{
- std::bool_constant< std::bool_constant<std::is_integral_v<_Tp>>() ||
- std::bool_constant<std::is_floating_point_v<_Tp>>() ||
- std::bool_constant<std::is_enum_v<_Tp>>() >()
+ std::bool_constant< std::bool_constant<std::is_integral_v<Key>>() ||
+ std::bool_constant<std::is_floating_point_v<Key>>() ||
+ std::bool_constant<std::is_enum_v<Key>>() >()
} -> std::same_as<std::true_type>;
}
-struct constexpr_hash<_Tp> {
- [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __v) const noexcept {
- if constexpr (std::is_integral_v<_Tp>) {
- if constexpr (sizeof(_Tp) <= sizeof(size_t)) {
+struct constexpr_hash<Key> {
+ [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& __v) const noexcept {
+ if constexpr (std::is_integral_v<Key>) {
+ if constexpr (sizeof(Key) <= sizeof(size_t)) {
return static_cast<size_t>(__v);
} else {
- constexpr size_t multiple = sizeof(_Tp) / sizeof(size_t);
+ constexpr size_t multiple = sizeof(Key) / sizeof(size_t);
std::array<size_t, multiple> region = std::bit_cast<std::array<size_t, multiple>>(__v);
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
- } else if constexpr (std::is_floating_point_v<_Tp>) {
+ } else if constexpr (std::is_floating_point_v<Key>) {
if (__v == 0.0f)
return 0;
- // return __scalar_hash<_Tp>::operator()(__v);
+ // return __scalar_hash<Key>::operator()(__v);
- constexpr size_t multiple = sizeof(_Tp) / sizeof(char);
+ constexpr size_t multiple = sizeof(Key) / sizeof(char);
std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(__v);
// TODO: pack indexing?
@@ -88,8 +88,8 @@ struct constexpr_hash<_Tp> {
// return region[multiple - 1]; // TODO: hash-ing
// return 1234ULL;
- } else if constexpr (std::is_enum_v<_Tp>) {
- using type = decltype(std::to_underlying(std::declval<_Tp>()));
+ } else if constexpr (std::is_enum_v<Key>) {
+ using type = decltype(std::to_underlying(std::declval<Key>()));
return constexpr_hash<type>()(static_cast<type>(__v));
}
__builtin_unreachable(); // todo: revisit
@@ -99,7 +99,7 @@ struct constexpr_hash<_Tp> {
constexpr_hash& operator=(const constexpr_hash&) = default;
};
-template <class _Tp>
+template <class Key>
struct constexpr_hash {
constexpr_hash() = delete;
constexpr_hash(const constexpr_hash&) = delete;
>From 933ac6376214e4c2da3527ea5fcec7f1c92f47fa Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 11 Oct 2026 13:06:36 +0100
Subject: [PATCH 15/22] [[nodiscard]]
---
libcxx/test/support/constexpr_hash.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index f1824de405a67..c2baef0b9399b 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -41,7 +41,7 @@ struct constexpr_hash<std::nullptr_t> {
constexpr_hash() noexcept = default;
constexpr_hash& operator=(const constexpr_hash&) = default;
- [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(std::nullptr_t) const noexcept {
+ [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(std::nullptr_t) const noexcept {
return 662607004ull;
}
};
@@ -57,7 +57,7 @@ template <typename Key>
} -> std::same_as<std::true_type>;
}
struct constexpr_hash<Key> {
- [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& __v) const noexcept {
+ [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& __v) const noexcept {
if constexpr (std::is_integral_v<Key>) {
if constexpr (sizeof(Key) <= sizeof(size_t)) {
return static_cast<size_t>(__v);
>From bbfa6908c282014b31ef2bce70794b3a17d02fc2 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 11 Oct 2026 13:16:09 +0100
Subject: [PATCH 16/22] move primary template up to avoid forward decl
---
libcxx/test/support/constexpr_hash.h | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index c2baef0b9399b..21d8a517eda1d 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -25,8 +25,12 @@ namespace support {
#if TEST_STD_VER >= 26
-template <typename Key>
-struct constexpr_hash;
+template <class Key>
+struct constexpr_hash {
+ constexpr_hash() = delete;
+ constexpr_hash(const constexpr_hash&) = delete;
+ constexpr_hash& operator=(const constexpr_hash&) = delete;
+};
// we need to disable hashing for `pointer` types, since we can't cast a pointer to a fixed width integer during constant evaluation via std::bit_cast, std::memcpy or union type-aliasing
template <class Key>
@@ -99,13 +103,6 @@ struct constexpr_hash<Key> {
constexpr_hash& operator=(const constexpr_hash&) = default;
};
-template <class Key>
-struct constexpr_hash {
- constexpr_hash() = delete;
- constexpr_hash(const constexpr_hash&) = delete;
- constexpr_hash& operator=(const constexpr_hash&) = delete;
-};
-
} // namespace support
#endif
>From 7e6ea831e463a0e0efcb51d7508b02219c270061 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Sun, 11 Oct 2026 13:19:24 +0100
Subject: [PATCH 17/22] key over __v
---
libcxx/test/support/constexpr_hash.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 21d8a517eda1d..9fe5efe2b51dd 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -61,25 +61,25 @@ template <typename Key>
} -> std::same_as<std::true_type>;
}
struct constexpr_hash<Key> {
- [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& __v) const noexcept {
+ [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& key) const noexcept {
if constexpr (std::is_integral_v<Key>) {
if constexpr (sizeof(Key) <= sizeof(size_t)) {
- return static_cast<size_t>(__v);
+ return static_cast<size_t>(key);
} else {
constexpr size_t multiple = sizeof(Key) / sizeof(size_t);
- std::array<size_t, multiple> region = std::bit_cast<std::array<size_t, multiple>>(__v);
+ std::array<size_t, multiple> region = std::bit_cast<std::array<size_t, multiple>>(key);
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
} else if constexpr (std::is_floating_point_v<Key>) {
- if (__v == 0.0f)
+ if (key == 0.0f)
return 0;
- // return __scalar_hash<Key>::operator()(__v);
+ // return __scalar_hash<Key>::operator()(key);
constexpr size_t multiple = sizeof(Key) / sizeof(char);
- std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(__v);
+ std::array<char, multiple> region = std::bit_cast<std::array<char, multiple>>(key);
// TODO: pack indexing?
size_t res = 0;
@@ -94,7 +94,7 @@ struct constexpr_hash<Key> {
} else if constexpr (std::is_enum_v<Key>) {
using type = decltype(std::to_underlying(std::declval<Key>()));
- return constexpr_hash<type>()(static_cast<type>(__v));
+ return constexpr_hash<type>()(static_cast<type>(key));
}
__builtin_unreachable(); // todo: revisit
}
>From cec5662c5a4e8090d6421d76407f8955dc5270e5 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Tue, 13 Oct 2026 19:00:57 +0100
Subject: [PATCH 18/22] use simpler concept
---
libcxx/test/support/constexpr_hash.h | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 9fe5efe2b51dd..922acb140ffa6 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -13,11 +13,11 @@
#ifndef SUPPORT_CONSTEXPR_HASH_H
#define SUPPORT_CONSTEXPR_HASH_H
-#include <__type_traits/is_unqualified.h>
#include <utility>
#include "test_macros.h"
#include <type_traits>
+#include <concepts>
#include <bit>
#include <cstddef>
@@ -51,18 +51,14 @@ struct constexpr_hash<std::nullptr_t> {
};
template <typename Key>
- requires requires(Key t) {
- { std::bool_constant<std::__is_unqualified_v<Key>>() } -> std::same_as<std::true_type>;
-
- {
- std::bool_constant< std::bool_constant<std::is_integral_v<Key>>() ||
- std::bool_constant<std::is_floating_point_v<Key>>() ||
- std::bool_constant<std::is_enum_v<Key>>() >()
- } -> std::same_as<std::true_type>;
- }
+concept UnqualifiedArithmeticOrEnum =
+ std::is_same_v<Key, std::remove_cvref_t<Key>> &&
+ (std::integral<Key> || std::floating_point<Key> || std::is_enum_v<Key>);
+
+template <UnqualifiedArithmeticOrEnum Key>
struct constexpr_hash<Key> {
[[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI size_t operator()(const Key& key) const noexcept {
- if constexpr (std::is_integral_v<Key>) {
+ if constexpr (std::integral<Key>) {
if constexpr (sizeof(Key) <= sizeof(size_t)) {
return static_cast<size_t>(key);
} else {
@@ -72,7 +68,7 @@ struct constexpr_hash<Key> {
// TODO: 0, 1, 2, 3, 4
return region[multiple - 1]; // TODO: hash-ing
}
- } else if constexpr (std::is_floating_point_v<Key>) {
+ } else if constexpr (std::floating_point<Key>) {
if (key == 0.0f)
return 0;
>From 5262c7d43d55e4fcf3c09482e18c918cbbea1f30 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Tue, 13 Oct 2026 19:15:23 +0100
Subject: [PATCH 19/22] std::unreachable
---
libcxx/test/support/constexpr_hash.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/support/constexpr_hash.h b/libcxx/test/support/constexpr_hash.h
index 922acb140ffa6..b303152ec5cce 100644
--- a/libcxx/test/support/constexpr_hash.h
+++ b/libcxx/test/support/constexpr_hash.h
@@ -92,7 +92,7 @@ struct constexpr_hash<Key> {
using type = decltype(std::to_underlying(std::declval<Key>()));
return constexpr_hash<type>()(static_cast<type>(key));
}
- __builtin_unreachable(); // todo: revisit
+ std::unreachable(); // todo: revisit
}
constexpr_hash() noexcept = default;
>From 16e829b6b67db49d479e1bfc95ceef17633592d8 Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Tue, 13 Oct 2026 20:26:29 +0100
Subject: [PATCH 20/22] 2 copies
---
.../unord.hash/enabled_hashes.pass.cpp | 5 -
.../function.objects/unord.hash/enum.pass.cpp | 39 ++---
.../unord.hash/floating.pass.cpp | 32 ++--
.../unord.hash/integral.pass.cpp | 144 ++++++++----------
.../unord.hash/non_enum.pass.cpp | 30 +---
.../unord.hash/pointer.pass.cpp | 30 ++--
.../constexpr_hash/enabled_hashes.pass.cpp | 31 ++++
.../constexpr_hash/enum.compile.fail.cpp | 25 +++
.../test.support/constexpr_hash/enum.pass.cpp | 88 +++++++++++
.../constexpr_hash/floating.pass.cpp | 96 ++++++++++++
.../constexpr_hash/integral.pass.cpp | 140 +++++++++++++++++
.../constexpr_hash/non_enum.pass.cpp | 53 +++++++
.../constexpr_hash/pointer.pass.cpp | 75 +++++++++
13 files changed, 618 insertions(+), 170 deletions(-)
create mode 100644 libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
create mode 100644 libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
index 43afca3407174..53d8ed788d866 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
@@ -18,14 +18,9 @@
#include "poisoned_hash_helper.h"
#include "test_macros.h"
-#include "constexpr_hash.h"
int main(int, char**) {
test_library_hash_specializations_available();
-#if TEST_STD_VER >= 26
- static_assert(test_constexpr_hash_specializations_available());
-#endif
-
return 0;
}
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
index cdc982f12c638..05a19329f909a 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/enum.pass.cpp
@@ -19,7 +19,6 @@
#include <limits>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
@@ -34,16 +33,17 @@ enum class EightBitColors : std::uint8_t { red, orange, yellow, green, blue, ind
enum Fruits { apple, pear, grape, mango, cantaloupe };
-template <class T, template <class> typename THash>
-TEST_CONSTEXPR_CXX26 void test() {
+template <class T>
+void
+test()
+{
#if TEST_STD_VER >= 11
test_hash_disabled<const T>();
test_hash_disabled<volatile T>();
test_hash_disabled<const volatile T>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef std::hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -52,8 +52,7 @@ TEST_CONSTEXPR_CXX26 void test() {
typedef typename std::underlying_type<T>::type under_type;
H h1;
- // std::hash<under_type> h2;
- THash<under_type> h2;
+ std::hash<under_type> h2;
for (int i = 0; i <= 5; ++i)
{
T t(static_cast<T> (i));
@@ -63,26 +62,16 @@ TEST_CONSTEXPR_CXX26 void test() {
}
}
-template <template <typename> typename THash >
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<Cardinals, THash>();
+int main(int, char**)
+{
+ test<Cardinals>();
- test<Colors, THash>();
- test<ShortColors, THash>();
- test<LongColors, THash>();
- test<EightBitColors, THash>();
+ test<Colors>();
+ test<ShortColors>();
+ test<LongColors>();
+ test<EightBitColors>();
- test<Fruits, THash>();
-
- return true;
-}
-
-int main(int, char**) {
- assert(test_with_hash<std::hash>());
-
-#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
-#endif
+ test<Fruits>();
return 0;
}
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
index c377aab5e869d..f6c31d068b231 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/floating.pass.cpp
@@ -25,23 +25,23 @@
#include <limits>
#include <cmath>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
# include "poisoned_hash_helper.h"
#endif
-template <class T, template <class> class THash = std::hash >
-TEST_CONSTEXPR_CXX26 void test() {
+template <class T>
+void
+test()
+{
#if TEST_STD_VER >= 11
- test_hash_disabled<const T, THash<const T>>();
- test_hash_disabled<volatile T, THash<volatile T>>();
- test_hash_disabled<const volatile T, THash<const volatile T>>();
+ test_hash_disabled<const T>();
+ test_hash_disabled<volatile T>();
+ test_hash_disabled<const volatile T>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef std::hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -78,19 +78,11 @@ TEST_CONSTEXPR_CXX26 void test() {
assert(pinf != ninf);
}
-template <template <typename> typename THash >
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<float, THash>();
- test<double, THash>();
- test<long double, THash>();
- return true;
-}
-
int main(int, char**)
{
- assert(test_with_hash<std::hash>());
-#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
-#endif
+ test<float>();
+ test<double>();
+ test<long double>();
+
return 0;
}
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index f2c217f10db96..c798b3aa77ea5 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -24,23 +24,23 @@
#include <limits>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
# include "poisoned_hash_helper.h"
#endif
-template <class T, template <class> class THash = std::hash >
-TEST_CONSTEXPR_CXX26 void test() {
+template <class T>
+void
+test()
+{
#if TEST_STD_VER >= 11
- test_hash_disabled<const T, THash<const T>>();
- test_hash_disabled<volatile T, THash<volatile T>>();
- test_hash_disabled<const volatile T, THash<const volatile T>>();
+ test_hash_disabled<const T>();
+ test_hash_disabled<volatile T>();
+ test_hash_disabled<const volatile T>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef std::hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -61,79 +61,69 @@ TEST_CONSTEXPR_CXX26 void test() {
}
}
-template <template <typename> typename THash >
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<bool, THash>();
- test<char, THash>();
- test<signed char, THash>();
- test<unsigned char, THash>();
- test<char16_t, THash>();
- test<char32_t, THash>();
+int main(int, char**)
+{
+ test<bool>();
+ test<char>();
+ test<signed char>();
+ test<unsigned char>();
+ test<char16_t>();
+ test<char32_t>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t, THash>();
+ test<wchar_t>();
#endif
- test<short, THash>();
- test<unsigned short, THash>();
- test<int, THash>();
- test<unsigned int, THash>();
- test<long, THash>();
- test<unsigned long, THash>();
- test<long long, THash>();
- test<unsigned long long, THash>();
-
- // LWG #2119
- test<std::ptrdiff_t, THash>();
- test<std::size_t, THash>();
-
- test<std::int8_t, THash>();
- test<std::int16_t, THash>();
- test<std::int32_t, THash>();
- test<std::int64_t, THash>();
-
- test<std::int_fast8_t, THash>();
- test<std::int_fast16_t, THash>();
- test<std::int_fast32_t, THash>();
- test<std::int_fast64_t, THash>();
-
- test<std::int_least8_t, THash>();
- test<std::int_least16_t, THash>();
- test<std::int_least32_t, THash>();
- test<std::int_least64_t, THash>();
-
- test<std::intmax_t, THash>();
- test<std::intptr_t, THash>();
-
- test<std::uint8_t, THash>();
- test<std::uint16_t, THash>();
- test<std::uint32_t, THash>();
- test<std::uint64_t, THash>();
-
- test<std::uint_fast8_t, THash>();
- test<std::uint_fast16_t, THash>();
- test<std::uint_fast32_t, THash>();
- test<std::uint_fast64_t, THash>();
-
- test<std::uint_least8_t, THash>();
- test<std::uint_least16_t, THash>();
- test<std::uint_least32_t, THash>();
- test<std::uint_least64_t, THash>();
-
- test<std::uintmax_t, THash>();
- test<std::uintptr_t, THash>();
+ test<short>();
+ test<unsigned short>();
+ test<int>();
+ test<unsigned int>();
+ test<long>();
+ test<unsigned long>();
+ test<long long>();
+ test<unsigned long long>();
+
+// LWG #2119
+ test<std::ptrdiff_t>();
+ test<std::size_t>();
+
+ test<std::int8_t>();
+ test<std::int16_t>();
+ test<std::int32_t>();
+ test<std::int64_t>();
+
+ test<std::int_fast8_t>();
+ test<std::int_fast16_t>();
+ test<std::int_fast32_t>();
+ test<std::int_fast64_t>();
+
+ test<std::int_least8_t>();
+ test<std::int_least16_t>();
+ test<std::int_least32_t>();
+ test<std::int_least64_t>();
+
+ test<std::intmax_t>();
+ test<std::intptr_t>();
+
+ test<std::uint8_t>();
+ test<std::uint16_t>();
+ test<std::uint32_t>();
+ test<std::uint64_t>();
+
+ test<std::uint_fast8_t>();
+ test<std::uint_fast16_t>();
+ test<std::uint_fast32_t>();
+ test<std::uint_fast64_t>();
+
+ test<std::uint_least8_t>();
+ test<std::uint_least16_t>();
+ test<std::uint_least32_t>();
+ test<std::uint_least64_t>();
+
+ test<std::uintmax_t>();
+ test<std::uintptr_t>();
#ifndef TEST_HAS_NO_INT128
- test<__int128_t, THash>();
- test<__uint128_t, THash>();
-#endif
-
- return true;
-}
-
-int main(int, char**) {
- assert(test_with_hash<std::hash>());
-
-#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ test<__int128_t>();
+ test<__uint128_t>();
#endif
return 0;
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
index 8632e907f1caf..94cc9d912f3a7 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
@@ -18,36 +18,22 @@
#include <cassert>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
struct X {};
-template <template <typename> typename THash >
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- using H = THash<X>;
-
- static_assert(!std::is_default_constructible<H>::value, "");
- static_assert(!std::is_copy_constructible<H>::value, "");
- static_assert(!std::is_move_constructible<H>::value, "");
- static_assert(!std::is_copy_assignable<H>::value, "");
- static_assert(!std::is_move_assignable<H>::value, "");
+int main(int, char**)
+{
+ using H = std::hash<X>;
+ static_assert(!std::is_default_constructible<H>::value, "");
+ static_assert(!std::is_copy_constructible<H>::value, "");
+ static_assert(!std::is_move_constructible<H>::value, "");
+ static_assert(!std::is_copy_assignable<H>::value, "");
+ static_assert(!std::is_move_assignable<H>::value, "");
#if TEST_STD_VER > 14
static_assert(!std::is_invocable<H, X&>::value, "");
static_assert(!std::is_invocable<H, X const&>::value, "");
#endif
- return true;
-}
-
-int main(int, char**) {
- assert(test_with_hash<std::hash>());
-
-#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
-#endif
- // using H = std::hash<X>;
- // using H = support::constexpr_hash<X>;
-
return 0;
}
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
index c6c2a6e805f2b..784831018a006 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/pointer.pass.cpp
@@ -24,13 +24,13 @@
#include <functional>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
-template <class T, template <class> class THash = std::hash >
-TEST_CONSTEXPR_CXX26 void test() {
- // typedef std::hash<T> H;
- typedef THash<T> H;
+template <class T>
+void
+test()
+{
+ typedef std::hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -44,11 +44,9 @@ TEST_CONSTEXPR_CXX26 void test() {
assert(h(&i) != h(&j));
}
-template < template <class> class THash = std::hash >
-TEST_CONSTEXPR_CXX26 void test_nullptr() {
+void test_nullptr() {
typedef std::nullptr_t T;
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef std::hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -56,20 +54,10 @@ TEST_CONSTEXPR_CXX26 void test_nullptr() {
ASSERT_NOEXCEPT(H()(T()));
}
-template <template <typename> typename THash >
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test_nullptr< THash>();
- return true;
-}
-
int main(int, char**)
{
- assert(test_with_hash<std::hash>());
- test<int*>();
-
-#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
-#endif
+ test<int*>();
+ test_nullptr();
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
new file mode 100644
index 0000000000000..43afca3407174
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// <functional>
+
+// Test that <functional> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <functional>
+
+#include "poisoned_hash_helper.h"
+
+#include "test_macros.h"
+#include "constexpr_hash.h"
+
+int main(int, char**) {
+ test_library_hash_specializations_available();
+
+#if TEST_STD_VER >= 26
+ static_assert(test_constexpr_hash_specializations_available());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp b/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
new file mode 100644
index 0000000000000..4401bc1b6507f
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <functional>
+
+// Hashing a struct w/o a defined hash should fail.
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+
+struct X {};
+
+int main(int, char**)
+{
+ X x;
+ std::size_t h = std::hash<X>{} ( x );
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
new file mode 100644
index 0000000000000..cdc982f12c638
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// <functional>
+
+// Make sure that we can hash enumeration values.
+
+#include <functional>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#include "constexpr_hash.h"
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+# include "poisoned_hash_helper.h"
+#endif
+
+enum class Colors { red, orange, yellow, green, blue, indigo, violet };
+enum class Cardinals { zero, one, two, three, five=5 };
+enum class LongColors : short { red, orange, yellow, green, blue, indigo, violet };
+enum class ShortColors : long { red, orange, yellow, green, blue, indigo, violet };
+enum class EightBitColors : std::uint8_t { red, orange, yellow, green, blue, indigo, violet };
+
+enum Fruits { apple, pear, grape, mango, cantaloupe };
+
+template <class T, template <class> typename THash>
+TEST_CONSTEXPR_CXX26 void test() {
+#if TEST_STD_VER >= 11
+ test_hash_disabled<const T>();
+ test_hash_disabled<volatile T>();
+ test_hash_disabled<const volatile T>();
+#endif
+
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
+#if TEST_STD_VER <= 17
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+#endif
+ ASSERT_NOEXCEPT(H()(T()));
+ typedef typename std::underlying_type<T>::type under_type;
+
+ H h1;
+ // std::hash<under_type> h2;
+ THash<under_type> h2;
+ for (int i = 0; i <= 5; ++i)
+ {
+ T t(static_cast<T> (i));
+ const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
+ if (small)
+ assert(h1(t) == h2(static_cast<under_type>(i)));
+ }
+}
+
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test<Cardinals, THash>();
+
+ test<Colors, THash>();
+ test<ShortColors, THash>();
+ test<LongColors, THash>();
+ test<EightBitColors, THash>();
+
+ test<Fruits, THash>();
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
new file mode 100644
index 0000000000000..c377aab5e869d
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// <functional>
+
+// template <class T>
+// struct hash
+// : public unary_function<T, size_t>
+// {
+// size_t operator()(T val) const;
+// };
+
+// Not very portable
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+#include <limits>
+#include <cmath>
+
+#include "constexpr_hash.h"
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+# include "poisoned_hash_helper.h"
+#endif
+
+template <class T, template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test() {
+#if TEST_STD_VER >= 11
+ test_hash_disabled<const T, THash<const T>>();
+ test_hash_disabled<volatile T, THash<volatile T>>();
+ test_hash_disabled<const volatile T, THash<const volatile T>>();
+#endif
+
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
+#if TEST_STD_VER <= 17
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+#endif
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
+
+ std::size_t t0 = h(0.);
+ std::size_t tn0 = h(-0.);
+ std::size_t tp1 = h(static_cast<T>(0.1));
+ std::size_t t1 = h(1);
+ std::size_t tn1 = h(-1);
+ std::size_t pinf = h(INFINITY);
+ std::size_t ninf = h(-INFINITY);
+ assert(t0 == tn0);
+ assert(t0 != tp1);
+ assert(t0 != t1);
+ assert(t0 != tn1);
+ assert(t0 != pinf);
+ assert(t0 != ninf);
+
+ assert(tp1 != t1);
+ assert(tp1 != tn1);
+ assert(tp1 != pinf);
+ assert(tp1 != ninf);
+
+ assert(t1 != tn1);
+ assert(t1 != pinf);
+ assert(t1 != ninf);
+
+ assert(tn1 != pinf);
+ assert(tn1 != ninf);
+
+ assert(pinf != ninf);
+}
+
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test<float, THash>();
+ test<double, THash>();
+ test<long double, THash>();
+ return true;
+}
+
+int main(int, char**)
+{
+ assert(test_with_hash<std::hash>());
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
new file mode 100644
index 0000000000000..f2c217f10db96
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// <functional>
+
+// template <class T>
+// struct hash
+// : public unary_function<T, size_t>
+// {
+// size_t operator()(T val) const;
+// };
+
+#include <functional>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#include "constexpr_hash.h"
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+# include "poisoned_hash_helper.h"
+#endif
+
+template <class T, template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test() {
+#if TEST_STD_VER >= 11
+ test_hash_disabled<const T, THash<const T>>();
+ test_hash_disabled<volatile T, THash<volatile T>>();
+ test_hash_disabled<const volatile T, THash<const volatile T>>();
+#endif
+
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
+#if TEST_STD_VER <= 17
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+#endif
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
+
+ for (int i = 0; i <= 5; ++i)
+ {
+ T t(static_cast<T>(i));
+ const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
+ if (small)
+ {
+ const std::size_t result = h(t);
+ LIBCPP_ASSERT(result == static_cast<std::size_t>(t));
+ ((void)result); // Prevent unused warning
+ }
+ }
+}
+
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test<bool, THash>();
+ test<char, THash>();
+ test<signed char, THash>();
+ test<unsigned char, THash>();
+ test<char16_t, THash>();
+ test<char32_t, THash>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t, THash>();
+#endif
+ test<short, THash>();
+ test<unsigned short, THash>();
+ test<int, THash>();
+ test<unsigned int, THash>();
+ test<long, THash>();
+ test<unsigned long, THash>();
+ test<long long, THash>();
+ test<unsigned long long, THash>();
+
+ // LWG #2119
+ test<std::ptrdiff_t, THash>();
+ test<std::size_t, THash>();
+
+ test<std::int8_t, THash>();
+ test<std::int16_t, THash>();
+ test<std::int32_t, THash>();
+ test<std::int64_t, THash>();
+
+ test<std::int_fast8_t, THash>();
+ test<std::int_fast16_t, THash>();
+ test<std::int_fast32_t, THash>();
+ test<std::int_fast64_t, THash>();
+
+ test<std::int_least8_t, THash>();
+ test<std::int_least16_t, THash>();
+ test<std::int_least32_t, THash>();
+ test<std::int_least64_t, THash>();
+
+ test<std::intmax_t, THash>();
+ test<std::intptr_t, THash>();
+
+ test<std::uint8_t, THash>();
+ test<std::uint16_t, THash>();
+ test<std::uint32_t, THash>();
+ test<std::uint64_t, THash>();
+
+ test<std::uint_fast8_t, THash>();
+ test<std::uint_fast16_t, THash>();
+ test<std::uint_fast32_t, THash>();
+ test<std::uint_fast64_t, THash>();
+
+ test<std::uint_least8_t, THash>();
+ test<std::uint_least16_t, THash>();
+ test<std::uint_least32_t, THash>();
+ test<std::uint_least64_t, THash>();
+
+ test<std::uintmax_t, THash>();
+ test<std::uintptr_t, THash>();
+
+#ifndef TEST_HAS_NO_INT128
+ test<__int128_t, THash>();
+ test<__uint128_t, THash>();
+#endif
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
new file mode 100644
index 0000000000000..8632e907f1caf
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/non_enum.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+// <functional>
+
+// Hashing a struct w/o a defined hash should *not* fail, but it should
+// create a type that is not constructible and not callable.
+// See also: https://cplusplus.github.io/LWG/lwg-defects.html#2543
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+
+#include "constexpr_hash.h"
+#include "test_macros.h"
+
+struct X {};
+
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ using H = THash<X>;
+
+ static_assert(!std::is_default_constructible<H>::value, "");
+ static_assert(!std::is_copy_constructible<H>::value, "");
+ static_assert(!std::is_move_constructible<H>::value, "");
+ static_assert(!std::is_copy_assignable<H>::value, "");
+ static_assert(!std::is_move_assignable<H>::value, "");
+#if TEST_STD_VER > 14
+ static_assert(!std::is_invocable<H, X&>::value, "");
+ static_assert(!std::is_invocable<H, X const&>::value, "");
+#endif
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test_with_hash<std::hash>());
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+ // using H = std::hash<X>;
+ // using H = support::constexpr_hash<X>;
+
+ return 0;
+}
diff --git a/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
new file mode 100644
index 0000000000000..c6c2a6e805f2b
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+// <functional>
+
+// template <class T>
+// struct hash
+// : public unary_function<T, size_t>
+// {
+// size_t operator()(T val) const;
+// };
+
+// Not very portable
+
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+
+#include "constexpr_hash.h"
+#include "test_macros.h"
+
+template <class T, template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test() {
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
+#if TEST_STD_VER <= 17
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+#endif
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
+
+ typedef typename std::remove_pointer<T>::type type;
+ type i;
+ type j;
+ assert(h(&i) != h(&j));
+}
+
+template < template <class> class THash = std::hash >
+TEST_CONSTEXPR_CXX26 void test_nullptr() {
+ typedef std::nullptr_t T;
+ // typedef std::hash<T> H;
+ typedef THash<T> H;
+#if TEST_STD_VER <= 17
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+#endif
+ ASSERT_NOEXCEPT(H()(T()));
+}
+
+template <template <typename> typename THash >
+TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+ test_nullptr< THash>();
+ return true;
+}
+
+int main(int, char**)
+{
+ assert(test_with_hash<std::hash>());
+ test<int*>();
+
+#if TEST_STD_VER >= 26
+ static_assert(test_with_hash<support::constexpr_hash>());
+#endif
+
+ return 0;
+}
>From d46cecf4672d7739c1dfd0568f41a9c55465758a Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Tue, 13 Oct 2026 21:41:22 +0100
Subject: [PATCH 21/22] setup support tests
---
.../unord.hash/enum.compile.fail.cpp | 3 +-
.../constexpr_hash/enabled_hashes.pass.cpp | 11 +-
.../constexpr_hash/enum.compile.fail.cpp | 17 +-
.../test.support/constexpr_hash/enum.pass.cpp | 64 ++++----
.../constexpr_hash/floating.pass.cpp | 102 ++++++------
.../constexpr_hash/integral.pass.cpp | 149 ++++++++----------
.../constexpr_hash/non_enum.pass.cpp | 20 +--
.../constexpr_hash/pointer.pass.cpp | 50 +++---
.../constexpr_hash/pointer.verify.cpp | 28 ++++
9 files changed, 215 insertions(+), 229 deletions(-)
create mode 100644 libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enum.compile.fail.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enum.compile.fail.cpp
index 4401bc1b6507f..a3b360f09599f 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/enum.compile.fail.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/enum.compile.fail.cpp
@@ -11,8 +11,7 @@
// Hashing a struct w/o a defined hash should fail.
#include <functional>
-#include <cassert>
-#include <type_traits>
+#include <cstddef>
struct X {};
diff --git a/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
index 43afca3407174..4fbb78d357bc0 100644
--- a/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
@@ -6,19 +6,18 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++26
-// <functional>
+// "support/constexpr_hash.h"
-// Test that <functional> provides all of the arithmetic, enum, and pointer
-// hash specializations.
+// Test that "support/constexpr_hash.h" provides all of the arithmetic, enum, and pointer
+// hash specializations, and that they work during constant evaluation.
-#include <functional>
+#include "constexpr_hash.h"
#include "poisoned_hash_helper.h"
#include "test_macros.h"
-#include "constexpr_hash.h"
int main(int, char**) {
test_library_hash_specializations_available();
diff --git a/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp b/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
index 4401bc1b6507f..733344466f6a1 100644
--- a/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/enum.compile.fail.cpp
@@ -6,20 +6,21 @@
//
//===----------------------------------------------------------------------===//
-// <functional>
+// REQUIRES: std-at-least-c++26
+
+// "support/constexpr_hash.h"
// Hashing a struct w/o a defined hash should fail.
-#include <functional>
-#include <cassert>
-#include <type_traits>
+#include "constexpr_hash.h"
+
+#include <cstddef>
struct X {};
-int main(int, char**)
-{
- X x;
- std::size_t h = std::hash<X>{} ( x );
+int main(int, char**) {
+ X x;
+ std::size_t h = support::constexpr_hash<X>{}(x);
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
index cdc982f12c638..1410d59f3f621 100644
--- a/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
@@ -8,18 +8,18 @@
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-// <functional>
+// "support/constexpr_hash.h"
// Make sure that we can hash enumeration values.
-#include <functional>
+#include "constexpr_hash.h"
+
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
@@ -27,61 +27,57 @@
#endif
enum class Colors { red, orange, yellow, green, blue, indigo, violet };
-enum class Cardinals { zero, one, two, three, five=5 };
+enum class Cardinals { zero, one, two, three, five = 5 };
enum class LongColors : short { red, orange, yellow, green, blue, indigo, violet };
enum class ShortColors : long { red, orange, yellow, green, blue, indigo, violet };
enum class EightBitColors : std::uint8_t { red, orange, yellow, green, blue, indigo, violet };
enum Fruits { apple, pear, grape, mango, cantaloupe };
-template <class T, template <class> typename THash>
+template <class T>
TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
- test_hash_disabled<const T>();
- test_hash_disabled<volatile T>();
- test_hash_disabled<const volatile T>();
+ test_hash_disabled<const T, support::constexpr_hash<const T>>();
+ test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
+ test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef support::constexpr_hash<T> H;
#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
#endif
- ASSERT_NOEXCEPT(H()(T()));
- typedef typename std::underlying_type<T>::type under_type;
-
- H h1;
- // std::hash<under_type> h2;
- THash<under_type> h2;
- for (int i = 0; i <= 5; ++i)
- {
- T t(static_cast<T> (i));
- const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
- if (small)
- assert(h1(t) == h2(static_cast<under_type>(i)));
- }
+ ASSERT_NOEXCEPT(H()(T()));
+ typedef typename std::underlying_type<T>::type under_type;
+
+ H h1;
+ support::constexpr_hash<under_type> h2;
+ for (int i = 0; i <= 5; ++i) {
+ T t(static_cast<T>(i));
+ const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
+ if (small)
+ assert(h1(t) == h2(static_cast<under_type>(i)));
+ }
}
-template <template <typename> typename THash >
TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<Cardinals, THash>();
+ test<Cardinals>();
- test<Colors, THash>();
- test<ShortColors, THash>();
- test<LongColors, THash>();
- test<EightBitColors, THash>();
+ test<Colors>();
+ test<ShortColors>();
+ test<LongColors>();
+ test<EightBitColors>();
- test<Fruits, THash>();
+ test<Fruits>();
return true;
}
int main(int, char**) {
- assert(test_with_hash<std::hash>());
+ assert(test_with_hash());
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ static_assert(test_with_hash());
#endif
return 0;
diff --git a/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
index c377aab5e869d..78d065f676a7a 100644
--- a/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
@@ -8,89 +8,79 @@
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-// <functional>
-
-// template <class T>
-// struct hash
-// : public unary_function<T, size_t>
-// {
-// size_t operator()(T val) const;
-// };
+// "support/constexpr_hash.h"
// Not very portable
-#include <functional>
+#include "constexpr_hash.h"
+
#include <cassert>
#include <type_traits>
#include <limits>
#include <cmath>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
# include "poisoned_hash_helper.h"
#endif
-template <class T, template <class> class THash = std::hash >
+template <class T>
TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
- test_hash_disabled<const T, THash<const T>>();
- test_hash_disabled<volatile T, THash<volatile T>>();
- test_hash_disabled<const volatile T, THash<const volatile T>>();
+ test_hash_disabled<const T, support::constexpr_hash<const T>>();
+ test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
+ test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef support::constexpr_hash<T> H;
#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
#endif
- ASSERT_NOEXCEPT(H()(T()));
- H h;
-
- std::size_t t0 = h(0.);
- std::size_t tn0 = h(-0.);
- std::size_t tp1 = h(static_cast<T>(0.1));
- std::size_t t1 = h(1);
- std::size_t tn1 = h(-1);
- std::size_t pinf = h(INFINITY);
- std::size_t ninf = h(-INFINITY);
- assert(t0 == tn0);
- assert(t0 != tp1);
- assert(t0 != t1);
- assert(t0 != tn1);
- assert(t0 != pinf);
- assert(t0 != ninf);
-
- assert(tp1 != t1);
- assert(tp1 != tn1);
- assert(tp1 != pinf);
- assert(tp1 != ninf);
-
- assert(t1 != tn1);
- assert(t1 != pinf);
- assert(t1 != ninf);
-
- assert(tn1 != pinf);
- assert(tn1 != ninf);
-
- assert(pinf != ninf);
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
+
+ std::size_t t0 = h(0.);
+ std::size_t tn0 = h(-0.);
+ std::size_t tp1 = h(static_cast<T>(0.1));
+ std::size_t t1 = h(1);
+ std::size_t tn1 = h(-1);
+ std::size_t pinf = h(INFINITY);
+ std::size_t ninf = h(-INFINITY);
+ assert(t0 == tn0);
+ assert(t0 != tp1);
+ assert(t0 != t1);
+ assert(t0 != tn1);
+ assert(t0 != pinf);
+ assert(t0 != ninf);
+
+ assert(tp1 != t1);
+ assert(tp1 != tn1);
+ assert(tp1 != pinf);
+ assert(tp1 != ninf);
+
+ assert(t1 != tn1);
+ assert(t1 != pinf);
+ assert(t1 != ninf);
+
+ assert(tn1 != pinf);
+ assert(tn1 != ninf);
+
+ assert(pinf != ninf);
}
-template <template <typename> typename THash >
TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<float, THash>();
- test<double, THash>();
- test<long double, THash>();
+ test<float>();
+ test<double>();
+ test<long double>();
return true;
}
-int main(int, char**)
-{
- assert(test_with_hash<std::hash>());
+int main(int, char**) {
+ assert(test_with_hash());
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ static_assert(test_with_hash());
#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
index f2c217f10db96..051084cac06f0 100644
--- a/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
@@ -8,132 +8,121 @@
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-// <functional>
+// "support/constexpr_hash.h"
-// template <class T>
-// struct hash
-// : public unary_function<T, size_t>
-// {
-// size_t operator()(T val) const;
-// };
+#include "constexpr_hash.h"
-#include <functional>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
#if TEST_STD_VER >= 11
# include "poisoned_hash_helper.h"
#endif
-template <class T, template <class> class THash = std::hash >
+template <class T>
TEST_CONSTEXPR_CXX26 void test() {
#if TEST_STD_VER >= 11
- test_hash_disabled<const T, THash<const T>>();
- test_hash_disabled<volatile T, THash<volatile T>>();
- test_hash_disabled<const volatile T, THash<const volatile T>>();
+ test_hash_disabled<const T, support::constexpr_hash<const T>>();
+ test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
+ test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
#endif
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef support::constexpr_hash<T> H;
#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
#endif
- ASSERT_NOEXCEPT(H()(T()));
- H h;
-
- for (int i = 0; i <= 5; ++i)
- {
- T t(static_cast<T>(i));
- const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
- if (small)
- {
- const std::size_t result = h(t);
- LIBCPP_ASSERT(result == static_cast<std::size_t>(t));
- ((void)result); // Prevent unused warning
- }
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
+
+ for (int i = 0; i <= 5; ++i) {
+ T t(static_cast<T>(i));
+ const bool small = std::integral_constant<bool, sizeof(T) <= sizeof(std::size_t)>::value; // avoid compiler warnings
+ if (small) {
+ const std::size_t result = h(t);
+ LIBCPP_ASSERT(result == static_cast<std::size_t>(t));
+ ((void)result); // Prevent unused warning
}
+ }
}
-template <template <typename> typename THash >
TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test<bool, THash>();
- test<char, THash>();
- test<signed char, THash>();
- test<unsigned char, THash>();
- test<char16_t, THash>();
- test<char32_t, THash>();
+ test<bool>();
+ test<char>();
+ test<signed char>();
+ test<unsigned char>();
+ test<char16_t>();
+ test<char32_t>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t, THash>();
+ test<wchar_t>();
#endif
- test<short, THash>();
- test<unsigned short, THash>();
- test<int, THash>();
- test<unsigned int, THash>();
- test<long, THash>();
- test<unsigned long, THash>();
- test<long long, THash>();
- test<unsigned long long, THash>();
+ test<short>();
+ test<unsigned short>();
+ test<int>();
+ test<unsigned int>();
+ test<long>();
+ test<unsigned long>();
+ test<long long>();
+ test<unsigned long long>();
// LWG #2119
- test<std::ptrdiff_t, THash>();
- test<std::size_t, THash>();
+ test<std::ptrdiff_t>();
+ test<std::size_t>();
- test<std::int8_t, THash>();
- test<std::int16_t, THash>();
- test<std::int32_t, THash>();
- test<std::int64_t, THash>();
+ test<std::int8_t>();
+ test<std::int16_t>();
+ test<std::int32_t>();
+ test<std::int64_t>();
- test<std::int_fast8_t, THash>();
- test<std::int_fast16_t, THash>();
- test<std::int_fast32_t, THash>();
- test<std::int_fast64_t, THash>();
+ test<std::int_fast8_t>();
+ test<std::int_fast16_t>();
+ test<std::int_fast32_t>();
+ test<std::int_fast64_t>();
- test<std::int_least8_t, THash>();
- test<std::int_least16_t, THash>();
- test<std::int_least32_t, THash>();
- test<std::int_least64_t, THash>();
+ test<std::int_least8_t>();
+ test<std::int_least16_t>();
+ test<std::int_least32_t>();
+ test<std::int_least64_t>();
- test<std::intmax_t, THash>();
- test<std::intptr_t, THash>();
+ test<std::intmax_t>();
+ test<std::intptr_t>();
- test<std::uint8_t, THash>();
- test<std::uint16_t, THash>();
- test<std::uint32_t, THash>();
- test<std::uint64_t, THash>();
+ test<std::uint8_t>();
+ test<std::uint16_t>();
+ test<std::uint32_t>();
+ test<std::uint64_t>();
- test<std::uint_fast8_t, THash>();
- test<std::uint_fast16_t, THash>();
- test<std::uint_fast32_t, THash>();
- test<std::uint_fast64_t, THash>();
+ test<std::uint_fast8_t>();
+ test<std::uint_fast16_t>();
+ test<std::uint_fast32_t>();
+ test<std::uint_fast64_t>();
- test<std::uint_least8_t, THash>();
- test<std::uint_least16_t, THash>();
- test<std::uint_least32_t, THash>();
- test<std::uint_least64_t, THash>();
+ test<std::uint_least8_t>();
+ test<std::uint_least16_t>();
+ test<std::uint_least32_t>();
+ test<std::uint_least64_t>();
- test<std::uintmax_t, THash>();
- test<std::uintptr_t, THash>();
+ test<std::uintmax_t>();
+ test<std::uintptr_t>();
#ifndef TEST_HAS_NO_INT128
- test<__int128_t, THash>();
- test<__uint128_t, THash>();
+ test<__int128_t>();
+ test<__uint128_t>();
#endif
return true;
}
int main(int, char**) {
- assert(test_with_hash<std::hash>());
+ assert(test_with_hash());
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ static_assert(test_with_hash());
#endif
return 0;
diff --git a/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
index 8632e907f1caf..4ee2887982ef8 100644
--- a/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
@@ -8,24 +8,22 @@
// UNSUPPORTED: c++03
-// <functional>
+// "support/constexpr_hash.h"
// Hashing a struct w/o a defined hash should *not* fail, but it should
// create a type that is not constructible and not callable.
// See also: https://cplusplus.github.io/LWG/lwg-defects.html#2543
-#include <functional>
+#include "constexpr_hash.h"
#include <cassert>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
struct X {};
-template <template <typename> typename THash >
TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- using H = THash<X>;
+ using H = support::constexpr_hash<X>;
static_assert(!std::is_default_constructible<H>::value, "");
static_assert(!std::is_copy_constructible<H>::value, "");
@@ -33,21 +31,19 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
static_assert(!std::is_copy_assignable<H>::value, "");
static_assert(!std::is_move_assignable<H>::value, "");
#if TEST_STD_VER > 14
- static_assert(!std::is_invocable<H, X&>::value, "");
- static_assert(!std::is_invocable<H, X const&>::value, "");
+ static_assert(!std::is_invocable<H, X&>::value, "");
+ static_assert(!std::is_invocable<H, X const&>::value, "");
#endif
- return true;
+ return true;
}
int main(int, char**) {
- assert(test_with_hash<std::hash>());
+ assert(test_with_hash());
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ static_assert(test_with_hash());
#endif
- // using H = std::hash<X>;
- // using H = support::constexpr_hash<X>;
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
index c6c2a6e805f2b..508d3d02b6325 100644
--- a/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
@@ -8,47 +8,37 @@
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
-// <functional>
-
-// template <class T>
-// struct hash
-// : public unary_function<T, size_t>
-// {
-// size_t operator()(T val) const;
-// };
+// "support/constexpr_hash.h"
// Not very portable
+#include "constexpr_hash.h"
+
#include <cassert>
#include <cstddef>
-#include <functional>
#include <type_traits>
-#include "constexpr_hash.h"
#include "test_macros.h"
-template <class T, template <class> class THash = std::hash >
+template <class T>
TEST_CONSTEXPR_CXX26 void test() {
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef support::constexpr_hash<T> H;
#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
+ static_assert((std::is_same<typename H::argument_type, T>::value), "");
+ static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
#endif
- ASSERT_NOEXCEPT(H()(T()));
- H h;
+ ASSERT_NOEXCEPT(H()(T()));
+ H h;
- typedef typename std::remove_pointer<T>::type type;
- type i;
- type j;
- assert(h(&i) != h(&j));
+ typedef typename std::remove_pointer<T>::type type;
+ type i;
+ type j;
+ assert(h(&i) != h(&j));
}
-template < template <class> class THash = std::hash >
TEST_CONSTEXPR_CXX26 void test_nullptr() {
typedef std::nullptr_t T;
- // typedef std::hash<T> H;
- typedef THash<T> H;
+ typedef support::constexpr_hash<T> H;
#if TEST_STD_VER <= 17
static_assert((std::is_same<typename H::argument_type, T>::value), "");
static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
@@ -56,19 +46,17 @@ TEST_CONSTEXPR_CXX26 void test_nullptr() {
ASSERT_NOEXCEPT(H()(T()));
}
-template <template <typename> typename THash >
TEST_CONSTEXPR_CXX26 bool test_with_hash() {
- test_nullptr< THash>();
+ test_nullptr();
return true;
}
-int main(int, char**)
-{
- assert(test_with_hash<std::hash>());
- test<int*>();
+int main(int, char**) {
+ assert(test_with_hash());
+ // test<int*>();
#if TEST_STD_VER >= 26
- static_assert(test_with_hash<support::constexpr_hash>());
+ static_assert(test_with_hash());
#endif
return 0;
diff --git a/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp b/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
new file mode 100644
index 0000000000000..5be4d3fb9af8c
--- /dev/null
+++ b/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
@@ -0,0 +1,28 @@
+
+
+#include "constexpr_hash.h"
+
+#include <cstddef>
+
+constexpr std::size_t test_pointer() {
+ typedef int* T;
+ typedef support::constexpr_hash<T> H;
+
+ //expected-error at +2 {{call to deleted constructor}}
+ //expected-error at +1 {{ does not provide a call operator}}
+ return (H()(T()));
+}
+
+int main(int, char**) {
+ typedef int* T;
+ typedef support::constexpr_hash<T> H;
+
+ //expected-error at +2 {{call to deleted constructor}}
+ //expected-error at +1 {{ does not provide a call operator}}
+ std::size_t h = (H()(T()));
+
+ //expected-error at +1 {{static assertion expression is not an integral constant expression}}
+ static_assert(0 != test_pointer());
+
+ return 0;
+}
\ No newline at end of file
>From bbf06f556f2d7ed48d3a4ded9ee528f84f58565b Mon Sep 17 00:00:00 2001
From: Vinay Deshmukh <vinay_deshmukh at outlook.com>
Date: Tue, 13 Oct 2026 21:49:50 +0100
Subject: [PATCH 22/22] only cpp26
---
.../constexpr_hash/enabled_hashes.pass.cpp | 2 --
.../test.support/constexpr_hash/enum.pass.cpp | 19 +++++------------
.../constexpr_hash/floating.pass.cpp | 18 ++++------------
.../constexpr_hash/integral.pass.cpp | 19 +++++------------
.../constexpr_hash/non_enum.pass.cpp | 9 +++-----
.../constexpr_hash/pointer.pass.cpp | 21 ++++++-------------
.../constexpr_hash/pointer.verify.cpp | 3 +++
7 files changed, 26 insertions(+), 65 deletions(-)
diff --git a/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
index 4fbb78d357bc0..7456e56d2bb03 100644
--- a/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/enabled_hashes.pass.cpp
@@ -22,9 +22,7 @@
int main(int, char**) {
test_library_hash_specializations_available();
-#if TEST_STD_VER >= 26
static_assert(test_constexpr_hash_specializations_available());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
index 1410d59f3f621..e10cc97d39bd0 100644
--- a/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/enum.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+// REQUIRES: std-at-least-c++26
// "support/constexpr_hash.h"
@@ -22,9 +22,7 @@
#include "test_macros.h"
-#if TEST_STD_VER >= 11
-# include "poisoned_hash_helper.h"
-#endif
+#include "poisoned_hash_helper.h"
enum class Colors { red, orange, yellow, green, blue, indigo, violet };
enum class Cardinals { zero, one, two, three, five = 5 };
@@ -35,18 +33,13 @@ enum class EightBitColors : std::uint8_t { red, orange, yellow, green, blue, ind
enum Fruits { apple, pear, grape, mango, cantaloupe };
template <class T>
-TEST_CONSTEXPR_CXX26 void test() {
-#if TEST_STD_VER >= 11
+constexpr void test() {
test_hash_disabled<const T, support::constexpr_hash<const T>>();
test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
-#endif
typedef support::constexpr_hash<T> H;
-#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
-#endif
+
ASSERT_NOEXCEPT(H()(T()));
typedef typename std::underlying_type<T>::type under_type;
@@ -60,7 +53,7 @@ TEST_CONSTEXPR_CXX26 void test() {
}
}
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+constexpr bool test_with_hash() {
test<Cardinals>();
test<Colors>();
@@ -76,9 +69,7 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
int main(int, char**) {
assert(test_with_hash());
-#if TEST_STD_VER >= 26
static_assert(test_with_hash());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
index 78d065f676a7a..5c51725b9bef5 100644
--- a/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/floating.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+// REQUIRES: std-at-least-c++26
// "support/constexpr_hash.h"
@@ -21,23 +21,15 @@
#include "test_macros.h"
-#if TEST_STD_VER >= 11
-# include "poisoned_hash_helper.h"
-#endif
+#include "poisoned_hash_helper.h"
template <class T>
-TEST_CONSTEXPR_CXX26 void test() {
-#if TEST_STD_VER >= 11
+constexpr void test() {
test_hash_disabled<const T, support::constexpr_hash<const T>>();
test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
-#endif
typedef support::constexpr_hash<T> H;
-#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
-#endif
ASSERT_NOEXCEPT(H()(T()));
H h;
@@ -70,7 +62,7 @@ TEST_CONSTEXPR_CXX26 void test() {
assert(pinf != ninf);
}
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+constexpr bool test_with_hash() {
test<float>();
test<double>();
test<long double>();
@@ -79,8 +71,6 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
int main(int, char**) {
assert(test_with_hash());
-#if TEST_STD_VER >= 26
static_assert(test_with_hash());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
index 051084cac06f0..a4c51f79b686f 100644
--- a/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/integral.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+// REQUIRES: std-at-least-c++26
// "support/constexpr_hash.h"
@@ -20,23 +20,16 @@
#include "test_macros.h"
-#if TEST_STD_VER >= 11
-# include "poisoned_hash_helper.h"
-#endif
+#include "poisoned_hash_helper.h"
template <class T>
-TEST_CONSTEXPR_CXX26 void test() {
-#if TEST_STD_VER >= 11
+constexpr void test() {
test_hash_disabled<const T, support::constexpr_hash<const T>>();
test_hash_disabled<volatile T, support::constexpr_hash<volatile T>>();
test_hash_disabled<const volatile T, support::constexpr_hash<const volatile T>>();
-#endif
typedef support::constexpr_hash<T> H;
-#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
-#endif
+
ASSERT_NOEXCEPT(H()(T()));
H h;
@@ -51,7 +44,7 @@ TEST_CONSTEXPR_CXX26 void test() {
}
}
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+constexpr bool test_with_hash() {
test<bool>();
test<char>();
test<signed char>();
@@ -121,9 +114,7 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
int main(int, char**) {
assert(test_with_hash());
-#if TEST_STD_VER >= 26
static_assert(test_with_hash());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
index 4ee2887982ef8..5555a8283ddc6 100644
--- a/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/non_enum.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++26
// "support/constexpr_hash.h"
@@ -22,7 +22,7 @@
struct X {};
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+constexpr bool test_with_hash() {
using H = support::constexpr_hash<X>;
static_assert(!std::is_default_constructible<H>::value, "");
@@ -30,10 +30,9 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
static_assert(!std::is_move_constructible<H>::value, "");
static_assert(!std::is_copy_assignable<H>::value, "");
static_assert(!std::is_move_assignable<H>::value, "");
-#if TEST_STD_VER > 14
+
static_assert(!std::is_invocable<H, X&>::value, "");
static_assert(!std::is_invocable<H, X const&>::value, "");
-#endif
return true;
}
@@ -41,9 +40,7 @@ TEST_CONSTEXPR_CXX26 bool test_with_hash() {
int main(int, char**) {
assert(test_with_hash());
-#if TEST_STD_VER >= 26
static_assert(test_with_hash());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
index 508d3d02b6325..e5899a305651d 100644
--- a/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/pointer.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+// REQUIRES: std-at-least-c++26
// "support/constexpr_hash.h"
@@ -21,12 +21,9 @@
#include "test_macros.h"
template <class T>
-TEST_CONSTEXPR_CXX26 void test() {
+constexpr void test() {
typedef support::constexpr_hash<T> H;
-#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
-#endif
+
ASSERT_NOEXCEPT(H()(T()));
H h;
@@ -36,28 +33,22 @@ TEST_CONSTEXPR_CXX26 void test() {
assert(h(&i) != h(&j));
}
-TEST_CONSTEXPR_CXX26 void test_nullptr() {
+constexpr void test_nullptr() {
typedef std::nullptr_t T;
typedef support::constexpr_hash<T> H;
-#if TEST_STD_VER <= 17
- static_assert((std::is_same<typename H::argument_type, T>::value), "");
- static_assert((std::is_same<typename H::result_type, std::size_t>::value), "");
-#endif
+
ASSERT_NOEXCEPT(H()(T()));
}
-TEST_CONSTEXPR_CXX26 bool test_with_hash() {
+constexpr bool test_with_hash() {
test_nullptr();
return true;
}
int main(int, char**) {
assert(test_with_hash());
- // test<int*>();
-#if TEST_STD_VER >= 26
static_assert(test_with_hash());
-#endif
return 0;
}
diff --git a/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp b/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
index 5be4d3fb9af8c..22345c452c832 100644
--- a/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
+++ b/libcxx/test/support/test.support/constexpr_hash/pointer.verify.cpp
@@ -1,4 +1,7 @@
+// REQUIRES: std-at-least-c++26
+
+// "support/constexpr_hash.h"
#include "constexpr_hash.h"
More information about the libcxx-commits
mailing list