[WebAssembly] Fix asan issue from https://reviews.llvm.org/D121349
[llvm-project.git] / libcxx / test / support / poisoned_hash_helper.h
bloba0271e4af1e44b6eb32305420cb6dde79bd88a37
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 #ifndef SUPPORT_POISONED_HASH_HELPER_H
10 #define SUPPORT_POISONED_HASH_HELPER_H
12 #include <cassert>
13 #include <type_traits>
14 #include <utility>
16 #include "test_macros.h"
17 #include "test_workarounds.h"
19 #if TEST_STD_VER < 11
20 #error this header may only be used in C++11 or newer
21 #endif
23 template <class ...Args> struct TypeList;
25 // Test that the specified Hash meets the requirements of an enabled hash
26 template <class Hash, class Key, class InputKey = Key>
27 void test_hash_enabled(InputKey const& key = InputKey{});
29 template <class T, class InputKey = T>
30 void test_hash_enabled_for_type(InputKey const& key = InputKey{}) {
31 return test_hash_enabled<std::hash<T>, T, InputKey>(key);
34 // Test that the specified Hash meets the requirements of a disabled hash.
35 template <class Hash, class Key>
36 void test_hash_disabled();
38 template <class T>
39 void test_hash_disabled_for_type() {
40 return test_hash_disabled<std::hash<T>, T>();
43 namespace PoisonedHashDetail {
44 enum Enum {};
45 enum EnumClass : bool {};
46 struct Class {};
49 // Each header that declares the template hash provides enabled
50 // specializations of hash for nullptr t and all cv-unqualified
51 // arithmetic, enumeration, and pointer types.
52 using LibraryHashTypes = TypeList<
53 #if TEST_STD_VER > 14
54 decltype(nullptr),
55 #endif
56 bool,
57 char,
58 signed char,
59 unsigned char,
60 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
61 wchar_t,
62 #endif
63 #ifndef TEST_HAS_NO_UNICODE_CHARS
64 char16_t,
65 char32_t,
66 #endif
67 short,
68 unsigned short,
69 int,
70 unsigned int,
71 long,
72 unsigned long,
73 long long,
74 unsigned long long,
75 #ifndef TEST_HAS_NO_INT128
76 __int128_t,
77 __uint128_t,
78 #endif
79 float,
80 double,
81 long double,
82 PoisonedHashDetail::Enum,
83 PoisonedHashDetail::EnumClass,
84 void*,
85 void const*,
86 PoisonedHashDetail::Class*
90 // Test that each of the library hash specializations for arithmetic types,
91 // enum types, and pointer types are available and enabled.
92 template <class Types = LibraryHashTypes>
93 void test_library_hash_specializations_available(Types = Types{});
96 namespace PoisonedHashDetail {
98 template <class T, class = typename T::foo_bar_baz>
99 constexpr bool instantiate(int) { return true; }
100 template <class> constexpr bool instantiate(long) { return true; }
101 template <class T> constexpr bool instantiate() { return instantiate<T>(0); }
103 template <class To>
104 struct ConvertibleToSimple {
105 operator To() const {
106 return To{};
110 template <class To>
111 struct ConvertibleTo {
112 To to{};
113 operator To&() & { return to; }
114 operator To const&() const & { return to; }
115 operator To&&() && { return std::move(to); }
116 operator To const&&() const && { return std::move(to); }
119 template <class Hasher, class Key, class Res = decltype(std::declval<Hasher&>()(std::declval<Key>()))>
120 constexpr bool can_hash(int) {
121 return std::is_same<Res, size_t>::value;
123 template <class, class>
124 constexpr bool can_hash(long) {
125 return false;
127 template <class Hasher, class Key>
128 constexpr bool can_hash() {
129 return can_hash<Hasher, Key>(0);
131 } // namespace PoisonedHashDetail
133 template <class Hash, class Key, class InputKey>
134 void test_hash_enabled(InputKey const& key) {
135 using namespace PoisonedHashDetail;
137 static_assert(std::is_destructible<Hash>::value, "");
138 // Enabled hash requirements
139 static_assert(std::is_default_constructible<Hash>::value, "");
140 static_assert(std::is_copy_constructible<Hash>::value, "");
141 static_assert(std::is_move_constructible<Hash>::value, "");
142 static_assert(std::is_copy_assignable<Hash>::value, "");
143 static_assert(std::is_move_assignable<Hash>::value, "");
145 #if TEST_STD_VER > 14
146 static_assert(std::is_swappable<Hash>::value, "");
147 #elif defined(_LIBCPP_VERSION)
148 static_assert(std::__is_swappable<Hash>::value, "");
149 #endif
151 // Hashable requirements
152 static_assert(can_hash<Hash, Key&>(), "");
153 static_assert(can_hash<Hash, Key const&>(), "");
154 static_assert(can_hash<Hash, Key&&>(), "");
155 static_assert(can_hash<Hash const, Key&>(), "");
156 static_assert(can_hash<Hash const, Key const&>(), "");
157 static_assert(can_hash<Hash const, Key&&>(), "");
159 static_assert(can_hash<Hash, ConvertibleToSimple<Key>&>(), "");
160 static_assert(can_hash<Hash, ConvertibleToSimple<Key> const&>(), "");
161 static_assert(can_hash<Hash, ConvertibleToSimple<Key>&&>(), "");
163 static_assert(can_hash<Hash, ConvertibleTo<Key>&>(), "");
164 static_assert(can_hash<Hash, ConvertibleTo<Key> const&>(), "");
165 static_assert(can_hash<Hash, ConvertibleTo<Key>&&>(), "");
166 static_assert(can_hash<Hash, ConvertibleTo<Key> const&&>(), "");
168 const Hash h{};
169 assert(h(key) == h(key));
173 template <class Hash, class Key>
174 void test_hash_disabled() {
175 using namespace PoisonedHashDetail;
177 // Disabled hash requirements
178 static_assert(!std::is_default_constructible<Hash>::value, "");
179 static_assert(!std::is_copy_constructible<Hash>::value, "");
180 static_assert(!std::is_move_constructible<Hash>::value, "");
181 static_assert(!std::is_copy_assignable<Hash>::value, "");
182 static_assert(!std::is_move_assignable<Hash>::value, "");
184 static_assert(!std::is_function<
185 typename std::remove_pointer<
186 typename std::remove_reference<Hash>::type
187 >::type
188 >::value, "");
190 // Hashable requirements
191 static_assert(!can_hash<Hash, Key&>(), "");
192 static_assert(!can_hash<Hash, Key const&>(), "");
193 static_assert(!can_hash<Hash, Key&&>(), "");
194 static_assert(!can_hash<Hash const, Key&>(), "");
195 static_assert(!can_hash<Hash const, Key const&>(), "");
196 static_assert(!can_hash<Hash const, Key&&>(), "");
198 static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&>(), "");
199 static_assert(!can_hash<Hash, ConvertibleToSimple<Key> const&>(), "");
200 static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&&>(), "");
202 static_assert(!can_hash<Hash, ConvertibleTo<Key>&>(), "");
203 static_assert(!can_hash<Hash, ConvertibleTo<Key> const&>(), "");
204 static_assert(!can_hash<Hash, ConvertibleTo<Key>&&>(), "");
205 static_assert(!can_hash<Hash, ConvertibleTo<Key> const&&>(), "");
209 template <class First, class ...Rest>
210 struct TypeList<First, Rest...> {
211 template <template <class> class Trait, bool Expect = true>
212 static constexpr bool assertTrait() {
213 static_assert(Trait<First>::value == Expect, "");
214 return TypeList<Rest...>::template assertTrait<Trait, Expect>();
217 template <class Trait>
218 static void applyTrait() {
219 Trait::template apply<First>();
220 TypeList<Rest...>::template applyTrait<Trait>();
224 template <>
225 struct TypeList<> {
226 template <template <class> class Trait, bool Expect = true>
227 static constexpr bool assertTrait() {
228 return true;
230 template <class Trait>
231 static void applyTrait() {}
235 struct TestLibraryTrait {
236 template <class Type>
237 static void apply() { test_hash_enabled<std::hash<Type>, Type>(); }
240 template <class Types>
241 void test_library_hash_specializations_available(Types) {
242 Types::template applyTrait<TestLibraryTrait >();
245 #endif // SUPPORT_POISONED_HASH_HELPER_H