@@ -26,6 +26,16 @@ namespace cpp {
2626#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
2727#endif
2828
29+ template <unsigned N>
30+ LIBC_INLINE static void inline_copy (const char *from, char *to) {
31+ #if __has_builtin(__builtin_memcpy_inline)
32+ __builtin_memcpy_inline (to, from, N);
33+ #else
34+ for (unsigned i = 0 ; i < N; ++i)
35+ to[i] = from[i];
36+ #endif // __has_builtin(__builtin_memcpy_inline)
37+ }
38+
2939// This implementation of bit_cast requires trivially-constructible To, to avoid
3040// UB in the implementation.
3141template <typename To, typename From>
@@ -43,16 +53,30 @@ bit_cast(const From &from) {
4353 To to{};
4454 char *dst = reinterpret_cast <char *>(&to);
4555 const char *src = reinterpret_cast <const char *>(&from);
46- #if __has_builtin(__builtin_memcpy_inline)
47- __builtin_memcpy_inline (dst, src, sizeof (To));
48- #else
49- for (unsigned i = 0 ; i < sizeof (To); ++i)
50- dst[i] = src[i];
51- #endif // __has_builtin(__builtin_memcpy_inline)
56+ inline_copy<sizeof (From)>(src, dst);
5257 return to;
5358#endif // __has_builtin(__builtin_bit_cast)
5459}
5560
61+ // The following simple bit copy from a smaller type to maybe-larger type.
62+ template <typename To, typename From>
63+ LIBC_INLINE constexpr cpp::enable_if_t <
64+ (sizeof (To) >= sizeof (From)) &&
65+ cpp::is_trivially_constructible<To>::value &&
66+ cpp::is_trivially_copyable<To>::value &&
67+ cpp::is_trivially_copyable<From>::value,
68+ void >
69+ bit_copy (const From &from, To &to) {
70+ MSAN_UNPOISON (&from, sizeof (From));
71+ if constexpr (sizeof (To) == sizeof (From)) {
72+ to = bit_cast<To>(from);
73+ } else {
74+ char *dst = reinterpret_cast <char *>(&to);
75+ const char *src = reinterpret_cast <const char *>(&from);
76+ inline_copy<sizeof (From)>(src, dst);
77+ }
78+ }
79+
5680template <typename T>
5781[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t <cpp::is_unsigned_v<T>,
5882 bool >
0 commit comments