From 19262fc5966ab569f21f3d440f8b001bca666f17 Mon Sep 17 00:00:00 2001 From: JF Bastien Date: Fri, 21 Sep 2018 14:31:25 +0000 Subject: [PATCH] [ADT] restrict bit_cast to trivially-constructible To Summary: As discussed in r341853 by blaikie, the reinterpret_cast was technically an aliasing violation. Restrict our bit_cast implementation to To which are trivially-constructible (and note the existing restriction to constexpr). Once we move to C++17 we can use a version of bit_cast without these restrictions, or if we care we can SFINAE a different implementation when To isn't trivially-constructible. Originally landed in r342710 and reverted in r342711 because is_trivially_copyable is only in GCC 5.1 and later. Reviewers: dblaikie, rsmith Subscribers: dexonsmith, kristina, llvm-commits Differential Revision: https://reviews.llvm.org/D52332 llvm-svn: 342739 --- llvm/include/llvm/ADT/bit.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h index 0e3832127120..a4aba7b6a9ee 100644 --- a/llvm/include/llvm/ADT/bit.h +++ b/llvm/include/llvm/ADT/bit.h @@ -20,8 +20,19 @@ namespace llvm { +// This implementation of bit_cast is different from the C++17 one in two ways: +// - It isn't constexpr because that requires compiler support. +// - It requires trivially-constructible To, to avoid UB in the implementation. template ::type +#if (__has_feature(is_trivially_constructible) && defined(_LIBCPP_VERSION)) || \ + (defined(__GNUC__) && __GNUC__ >= 5) + , typename = typename std::is_trivially_constructible::type +#elif __has_feature(is_trivially_constructible) + , typename = typename std::enable_if<__is_trivially_constructible(To)>::type +#else + // See comment below. +#endif #if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \ (defined(__GNUC__) && __GNUC__ >= 5) , typename = typename std::enable_if::value>::type @@ -38,17 +49,9 @@ template inline To bit_cast(const From &from) noexcept { - alignas(To) unsigned char storage[sizeof(To)]; - std::memcpy(&storage, &from, sizeof(To)); -#if defined(__GNUC__) - // Before GCC 7.2, GCC thought that this violated strict aliasing. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - return reinterpret_cast(storage); -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif + To to; + std::memcpy(&to, &from, sizeof(To)); + return to; } } // namespace llvm