Index: llvm/include/llvm/Support/Bitfields.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/Bitfields.h @@ -0,0 +1,46 @@ +//===-- llvm/Support/BitFields.h - Utilities for C++ bit-fields -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Utilities for wrangling C++ bit-fields. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BIT_FIELDS_H +#define LLVM_SUPPORT_BIT_FIELDS_H + +#include "llvm/Support/MathExtras.h" +#include + +/// Given a bitfield Dst, does Dst = Src, and asserts that Src fits into Dst. +/// +/// Dst must be a bitfield with an unsigned integral underlying type. +/// +/// For example: +/// +/// \code +/// struct T { +/// unsigned X : 2; +/// }; +/// +/// T t; +/// LLVM_CHECKED_BITFIELD_ASSIGN(t.X, 3); // t.X = 3; +/// LLVM_CHECKED_BITFIELD_ASSIGN(t.X, 42); // error: 42 doesn't fit in T::X. +/// \endcode +/// +#define LLVM_CHECKED_BITFIELD_ASSIGN(Dst, Src) \ + do { \ + uint64_t _LlvmCheckedBitfieldAssignVal = (Src); \ + static_assert(std::is_unsigned::value, \ + #Dst " must be an unsigned integer type."); \ + (Dst) = _LlvmCheckedBitfieldAssignVal; \ + assert((Dst) == _LlvmCheckedBitfieldAssignVal && #Src \ + " is too wide to fit inside " #Dst); \ + } while (0) + +#endif Index: llvm/unittests/Support/BitfieldsTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Support/BitfieldsTest.cpp @@ -0,0 +1,55 @@ +//===- unittests/Support/MathExtrasTest.cpp - math utils tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Bitfields.h" +#include "gtest/gtest-death-test.h" +#include "gtest/gtest.h" + +namespace { + +TEST(BitfieldsTest, BitfieldAssign) { + struct { + unsigned a : 1; + uint32_t b : 32; + uint64_t c : 64; + } S; + + LLVM_CHECKED_BITFIELD_ASSIGN(S.a, 0); + EXPECT_EQ(0U, S.a); + LLVM_CHECKED_BITFIELD_ASSIGN(S.a, 1); + EXPECT_EQ(1U, S.a); + + LLVM_CHECKED_BITFIELD_ASSIGN(S.b, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.b); + LLVM_CHECKED_BITFIELD_ASSIGN(S.b, 0); + EXPECT_EQ(0U, S.b); + LLVM_CHECKED_BITFIELD_ASSIGN(S.b, 42); + EXPECT_EQ(42U, S.b); + + LLVM_CHECKED_BITFIELD_ASSIGN(S.c, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.c); + LLVM_CHECKED_BITFIELD_ASSIGN(S.c, std::numeric_limits::max()); + EXPECT_EQ(std::numeric_limits::max(), S.c); + LLVM_CHECKED_BITFIELD_ASSIGN(S.c, 0); + EXPECT_EQ(0U, S.c); +} + +TEST(BitfieldsDeathTest, BitfieldAssignOutOfRange) { + struct { + unsigned a : 1; + uint32_t b : 31; + uint64_t c : 63; + } S; + + EXPECT_DEBUG_DEATH(LLVM_CHECKED_BITFIELD_ASSIGN(S.a, 2), ""); + EXPECT_DEBUG_DEATH(LLVM_CHECKED_BITFIELD_ASSIGN(S.b, (1U << 31) + 1), ""); + EXPECT_DEBUG_DEATH(LLVM_CHECKED_BITFIELD_ASSIGN(S.b, (1LLU << 63) + 1), ""); +} + +} // namespace Index: llvm/unittests/Support/CMakeLists.txt =================================================================== --- llvm/unittests/Support/CMakeLists.txt +++ llvm/unittests/Support/CMakeLists.txt @@ -6,6 +6,7 @@ AlignOfTest.cpp AllocatorTest.cpp ArrayRecyclerTest.cpp + BitfieldsTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp