From 385e60b5b5b4dfff8d12ae9c19660d87fcef0e7e Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Thu, 4 Sep 2025 21:26:23 +0200 Subject: [PATCH] Fix EnumFlags compilation for large enums The EnumFlags fails to compile when the underlying enum has 30 or more elements. With exactly 32 elements the compilation error is the following: note: shift count 32 >= width of type 'int' (32 bits) static constexpr auto MaxRep{((1 << (Max_u_v - Min_u_v + 1)) - 1) << Min_u_v}; // largest representable value With 30 or 31 elements the compilation error is: note: value -2147483649 is outside the range of representable values of type 'int' static constexpr auto MaxRep{((1 << (Max_u_v - Min_u_v + 1)) - 1) << Min_u_v}; // largest representable value The solution consists in using "1ULL" literals in the MaxRep expression, such that the bit shifts are performed on a variable with at least 64-bits. --- Common/Utils/include/CommonUtils/EnumFlags.h | 5 ++- Common/Utils/test/testEnumFlags.cxx | 47 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Common/Utils/include/CommonUtils/EnumFlags.h b/Common/Utils/include/CommonUtils/EnumFlags.h index fcd7d2d9e5e26..9a8960f612553 100644 --- a/Common/Utils/include/CommonUtils/EnumFlags.h +++ b/Common/Utils/include/CommonUtils/EnumFlags.h @@ -160,8 +160,9 @@ struct FlagsHelper final { static constexpr auto Max_v{Values.back()}; // Enum last entry static constexpr auto Min_u_v{static_cast(Min_v)}; // Enum first entry as size_t static constexpr auto Max_u_v{static_cast(Max_v)}; // Enum last entry as size_t - static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous - static constexpr auto MaxRep{((1 << (Max_u_v - Min_u_v + 1)) - 1) << Min_u_v}; // largest representable value + static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range defered from underlying type"); + static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous + static constexpr auto MaxRep{((1ULL << (static_cast(Max_u_v - Min_u_v) + 1ULL)) - 1ULL) << Min_u_v}; // largest representable value template static constexpr std::string_view getName() diff --git a/Common/Utils/test/testEnumFlags.cxx b/Common/Utils/test/testEnumFlags.cxx index 5c8b71eb9040a..41b43bc4218ff 100644 --- a/Common/Utils/test/testEnumFlags.cxx +++ b/Common/Utils/test/testEnumFlags.cxx @@ -28,6 +28,46 @@ enum class TestEnum : uint8_t { Bit5VeryLongName, }; +// Very long enum +// to test that it works beyond 32 bits +enum class TestEnumLong : uint64_t { + Bit1, + Bit2, + Bit3, + Bit4, + Bit5, + Bit6, + Bit7, + Bit8, + Bit9, + Bit10, + Bit11, + Bit12, + Bit13, + Bit14, + Bit15, + Bit16, + Bit17, + Bit18, + Bit19, + Bit20, + Bit21, + Bit22, + Bit23, + Bit24, + Bit25, + Bit26, + Bit27, + Bit28, + Bit29, + Bit30, + Bit31, + Bit32, + Bit33, + Bit34, + // ... +}; + BOOST_AUTO_TEST_CASE(Flags_test) { using EFlags = o2::utils::EnumFlags; @@ -257,4 +297,11 @@ BOOST_AUTO_TEST_CASE(Flags_test) EFlags flags3{TestEnum::Bit4}; BOOST_CHECK(!flags1.contains(flags3)); // flags1 does not contain flags3 } + + { + // Test compilation using an enum with more than 32 bits + o2::utils::EnumFlags test; + test.set("Bit32"); + BOOST_CHECK(test.test(TestEnumLong::Bit32)); + } }