1 //===- llvm/unittest/ADT/BitmaskEnumTest.cpp - BitmaskEnum unit tests -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/BitmaskEnum.h" 10 #include "gtest/gtest.h" 11 12 using namespace llvm; 13 14 namespace { 15 enum Flags { 16 F0 = 0, 17 F1 = 1, 18 F2 = 2, 19 F3 = 4, 20 F4 = 8, 21 LLVM_MARK_AS_BITMASK_ENUM(F4) 22 }; 23 24 static_assert(is_bitmask_enum<Flags>::value != 0); 25 static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4); 26 27 enum Flags2 { V0 = 0, V1 = 1, V2 = 2, V3 = 4, V4 = 8 }; 28 } // namespace 29 30 namespace llvm { 31 LLVM_DECLARE_ENUM_AS_BITMASK(Flags2, V4); 32 } 33 34 static_assert(is_bitmask_enum<Flags>::value != 0); 35 static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4); 36 37 namespace { 38 TEST(BitmaskEnumTest, BitwiseOr) { 39 Flags f = F1 | F2; 40 EXPECT_EQ(3, f); 41 42 f = f | F3; 43 EXPECT_EQ(7, f); 44 45 Flags2 f2 = V1 | V2; 46 EXPECT_EQ(3, f2); 47 48 f2 = f2 | V3; 49 EXPECT_EQ(7, f2); 50 } 51 52 TEST(BitmaskEnumTest, BitwiseOrEquals) { 53 Flags f = F1; 54 f |= F3; 55 EXPECT_EQ(5, f); 56 57 // |= should return a reference to the LHS. 58 f = F2; 59 (f |= F3) = F1; 60 EXPECT_EQ(F1, f); 61 62 Flags2 f2 = V1; 63 f2 |= V3; 64 EXPECT_EQ(5, f2); 65 66 f2 = V2; 67 (f2 |= V3) = V1; 68 EXPECT_EQ(V1, f2); 69 } 70 71 TEST(BitmaskEnumTest, BitwiseAnd) { 72 Flags f = static_cast<Flags>(3) & F2; 73 EXPECT_EQ(F2, f); 74 75 f = (f | F3) & (F1 | F2 | F3); 76 EXPECT_EQ(6, f); 77 78 Flags2 f2 = static_cast<Flags2>(3) & V2; 79 EXPECT_EQ(V2, f2); 80 81 f2 = (f2 | V3) & (V1 | V2 | V3); 82 EXPECT_EQ(6, f2); 83 } 84 85 TEST(BitmaskEnumTest, BitwiseAndEquals) { 86 Flags f = F1 | F2 | F3; 87 f &= F1 | F2; 88 EXPECT_EQ(3, f); 89 90 // &= should return a reference to the LHS. 91 (f &= F1) = F3; 92 EXPECT_EQ(F3, f); 93 94 Flags2 f2 = V1 | V2 | V3; 95 f2 &= V1 | V2; 96 EXPECT_EQ(3, f2); 97 98 (f2 &= V1) = V3; 99 EXPECT_EQ(V3, f2); 100 } 101 102 TEST(BitmaskEnumTest, BitwiseXor) { 103 Flags f = (F1 | F2) ^ (F2 | F3); 104 EXPECT_EQ(5, f); 105 106 f = f ^ F1; 107 EXPECT_EQ(4, f); 108 109 Flags2 f2 = (V1 | V2) ^ (V2 | V3); 110 EXPECT_EQ(5, f2); 111 112 f2 = f2 ^ V1; 113 EXPECT_EQ(4, f2); 114 } 115 116 TEST(BitmaskEnumTest, BitwiseXorEquals) { 117 Flags f = (F1 | F2); 118 f ^= (F2 | F4); 119 EXPECT_EQ(9, f); 120 121 // ^= should return a reference to the LHS. 122 (f ^= F4) = F3; 123 EXPECT_EQ(F3, f); 124 125 Flags2 f2 = (V1 | V2); 126 f2 ^= (V2 | V4); 127 EXPECT_EQ(9, f2); 128 129 (f2 ^= V4) = V3; 130 EXPECT_EQ(V3, f2); 131 } 132 133 TEST(BitmaskEnumTest, BitwiseShift) { 134 Flags f = (F1 << F1); 135 EXPECT_EQ(f, F2); 136 137 Flags f2 = F1; 138 f2 <<= F1; 139 EXPECT_EQ(f2, F2); 140 141 Flags f3 = (F1 >> F1); 142 EXPECT_EQ(f3, F0); 143 144 Flags f4 = F1; 145 f4 >>= F1; 146 EXPECT_EQ(f4, F0); 147 } 148 149 TEST(BitmaskEnumTest, ConstantExpression) { 150 constexpr Flags f1 = ~F1; 151 constexpr Flags f2 = F1 | F2; 152 constexpr Flags f3 = F1 & F2; 153 constexpr Flags f4 = F1 ^ F2; 154 EXPECT_EQ(f1, ~F1); 155 EXPECT_EQ(f2, F1 | F2); 156 EXPECT_EQ(f3, F1 & F2); 157 EXPECT_EQ(f4, F1 ^ F2); 158 159 constexpr Flags2 f21 = ~V1; 160 constexpr Flags2 f22 = V1 | V2; 161 constexpr Flags2 f23 = V1 & V2; 162 constexpr Flags2 f24 = V1 ^ V2; 163 EXPECT_EQ(f21, ~V1); 164 EXPECT_EQ(f22, V1 | V2); 165 EXPECT_EQ(f23, V1 & V2); 166 EXPECT_EQ(f24, V1 ^ V2); 167 } 168 169 TEST(BitmaskEnumTest, BitwiseNot) { 170 Flags f = ~F1; 171 EXPECT_EQ(14, f); // Largest value for f is 15. 172 EXPECT_EQ(15, ~F0); 173 174 Flags2 f2 = ~V1; 175 EXPECT_EQ(14, f2); 176 EXPECT_EQ(15, ~V0); 177 } 178 179 enum class FlagsClass { 180 F0 = 0, 181 F1 = 1, 182 F2 = 2, 183 F3 = 4, 184 LLVM_MARK_AS_BITMASK_ENUM(F3) 185 }; 186 187 TEST(BitmaskEnumTest, ScopedEnum) { 188 FlagsClass f = (FlagsClass::F1 & ~FlagsClass::F0) | FlagsClass::F2; 189 f |= FlagsClass::F3; 190 EXPECT_EQ(7, static_cast<int>(f)); 191 } 192 193 struct Container { 194 enum Flags { F0 = 0, F1 = 1, F2 = 2, F3 = 4, LLVM_MARK_AS_BITMASK_ENUM(F3) }; 195 196 static Flags getFlags() { 197 Flags f = F0 | F1; 198 f |= F2; 199 return f; 200 } 201 }; 202 203 TEST(BitmaskEnumTest, EnumInStruct) { EXPECT_EQ(3, Container::getFlags()); } 204 205 } // namespace 206 207 namespace foo { 208 namespace bar { 209 namespace { 210 enum FlagsInNamespace { 211 F0 = 0, 212 F1 = 1, 213 F2 = 2, 214 F3 = 4, 215 LLVM_MARK_AS_BITMASK_ENUM(F3) 216 }; 217 } // namespace 218 } // namespace foo 219 } // namespace bar 220 221 namespace { 222 TEST(BitmaskEnumTest, EnumInNamespace) { 223 foo::bar::FlagsInNamespace f = ~foo::bar::F0 & (foo::bar::F1 | foo::bar::F2); 224 f |= foo::bar::F3; 225 EXPECT_EQ(7, f); 226 } 227 } // namespace 228