diff --git a/src/vt/utils/bits/bits_packer.h b/src/vt/utils/bits/bits_packer.h index c98de3286f..92e4963b1a 100644 --- a/src/vt/utils/bits/bits_packer.h +++ b/src/vt/utils/bits/bits_packer.h @@ -46,9 +46,27 @@ #include #include +#include namespace vt { namespace utils { +// Non-constexpr C++14 version of bit_cast +// See: https://en.cppreference.com/w/cpp/numeric/bit_cast +template +std::enable_if_t< + sizeof(Dst) == sizeof(Src) + && std::is_trivially_copyable::value + && std::is_trivially_copyable::value + && std::is_trivially_constructible::value, + Dst +> +bit_cast(const Src &src) { + Dst dst; + std::memcpy(&dst, &src, sizeof(Dst)); + return dst; +} + + struct BitPacker { using FieldType = int64_t; using FieldUnsignedType = uint64_t; diff --git a/src/vt/utils/bits/bits_packer.impl.h b/src/vt/utils/bits/bits_packer.impl.h index 5d89221a2d..19c1ed76c4 100644 --- a/src/vt/utils/bits/bits_packer.impl.h +++ b/src/vt/utils/bits/bits_packer.impl.h @@ -115,9 +115,16 @@ template BitPacker::setFieldDynamic( FieldType start, FieldType len, BitField& field, BitType const& segment ) { + // make_unsigned UB before C++20 for non-integral or bool types (ill-formed after C++20) + static_assert(std::is_integral::value && !std::is_same::value, + "BitField must be non-bool integral type"); + // sizeof(UnsignedBitField) is guaranteed to be the same as sizeof(BitField) + using UnsignedBitField = std::make_unsigned_t; auto const nbits = (sizeof(BitField) * 8) - len; field = field & ~(gen_bit_mask(len) << start); - field = field | (((static_cast(segment) << nbits) >> nbits) << start); + auto seg = bit_cast(static_cast(segment)); + UnsignedBitField bits = ((seg << nbits) >> nbits) << start; + field = field | bit_cast( bits ); } template