TestTypedEnum.cpp (18992B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/Assertions.h" 8 #include "mozilla/TypedEnumBits.h" 9 10 #include <stdint.h> 11 #include <type_traits> 12 13 // A rough feature check for is_literal_type. Not very carefully checked. 14 // Feel free to amend as needed. is_literal_type was removed in C++20. 15 // We leave ANDROID out because it's using stlport which doesn't have 16 // std::is_literal_type. 17 #if __cplusplus >= 201103L && __cplusplus < 202002L && !defined(ANDROID) 18 # if defined(__clang__) 19 /* 20 * Per Clang documentation, "Note that marketing version numbers should not 21 * be used to check for language features, as different vendors use different 22 * numbering schemes. Instead, use the feature checking macros." 23 */ 24 # ifndef __has_extension 25 # define __has_extension \ 26 __has_feature /* compatibility, for older versions of clang */ 27 # endif 28 # if __has_extension(is_literal) && __has_include(<type_traits>) 29 # define MOZ_HAVE_IS_LITERAL 30 # endif 31 # elif defined(__GNUC__) || defined(_MSC_VER) 32 # define MOZ_HAVE_IS_LITERAL 33 # endif 34 #endif 35 36 #if defined(MOZ_HAVE_IS_LITERAL) && defined(MOZ_HAVE_CXX11_CONSTEXPR) 37 # include <type_traits> 38 template <typename T> 39 void RequireLiteralType() { 40 static_assert(std::is_literal_type<T>::value, "Expected a literal type"); 41 } 42 #else // not MOZ_HAVE_IS_LITERAL 43 template <typename T> 44 void RequireLiteralType() {} 45 #endif 46 47 template <typename T> 48 void RequireLiteralType(const T&) { 49 RequireLiteralType<T>(); 50 } 51 52 enum class AutoEnum { A, B = -3, C }; 53 54 enum class CharEnum : char { A, B = 3, C }; 55 56 enum class AutoEnumBitField { A = 0x10, B = 0x20, C }; 57 58 enum class CharEnumBitField : char { A = 0x10, B, C = 0x40 }; 59 60 struct Nested { 61 enum class AutoEnum { A, B, C = -1 }; 62 63 enum class CharEnum : char { A = 4, B, C = 1 }; 64 65 enum class AutoEnumBitField { A, B = 0x20, C }; 66 67 enum class CharEnumBitField : char { A = 1, B = 1, C = 1 }; 68 }; 69 70 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField) 71 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField) 72 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField) 73 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField) 74 75 #define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \ 76 enum class BitFieldFor_##IntType : IntType{ \ 77 A = 1, \ 78 B = 2, \ 79 C = 4, \ 80 }; \ 81 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType) 82 83 MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t) 84 MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t) 85 MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t) 86 MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t) 87 MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t) 88 MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t) 89 MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t) 90 MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t) 91 MAKE_STANDARD_BITFIELD_FOR_TYPE(char) 92 typedef signed char signed_char; 93 MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char) 94 typedef unsigned char unsigned_char; 95 MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char) 96 MAKE_STANDARD_BITFIELD_FOR_TYPE(short) 97 typedef unsigned short unsigned_short; 98 MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short) 99 MAKE_STANDARD_BITFIELD_FOR_TYPE(int) 100 typedef unsigned int unsigned_int; 101 MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int) 102 MAKE_STANDARD_BITFIELD_FOR_TYPE(long) 103 typedef unsigned long unsigned_long; 104 MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long) 105 typedef long long long_long; 106 MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long) 107 typedef unsigned long long unsigned_long_long; 108 MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long) 109 110 #undef MAKE_STANDARD_BITFIELD_FOR_TYPE 111 112 template <typename T> 113 void TestNonConvertibilityForOneType() { 114 static_assert(!std::is_convertible_v<T, bool>, "should not be convertible"); 115 static_assert(!std::is_convertible_v<T, int>, "should not be convertible"); 116 static_assert(!std::is_convertible_v<T, uint64_t>, 117 "should not be convertible"); 118 119 static_assert(!std::is_convertible_v<bool, T>, "should not be convertible"); 120 static_assert(!std::is_convertible_v<int, T>, "should not be convertible"); 121 static_assert(!std::is_convertible_v<uint64_t, T>, 122 "should not be convertible"); 123 } 124 125 template <typename TypedEnum> 126 void TestTypedEnumBasics() { 127 const TypedEnum a = TypedEnum::A; 128 int unused = int(a); 129 (void)unused; 130 RequireLiteralType(TypedEnum::A); 131 RequireLiteralType(a); 132 TestNonConvertibilityForOneType<TypedEnum>(); 133 } 134 135 // Op wraps a bitwise binary operator, passed as a char template parameter, 136 // and applies it to its arguments (aT1, aT2). For example, 137 // 138 // Op<'|'>(aT1, aT2) 139 // 140 // is the same as 141 // 142 // aT1 | aT2. 143 // 144 template <char o, typename T1, typename T2> 145 auto Op(const T1& aT1, const T2& aT2) 146 -> decltype(aT1 | aT2) // See the static_assert's below --- the return type 147 // depends solely on the operands type, not on the 148 // choice of operation. 149 { 150 static_assert(std::is_same_v<decltype(aT1 | aT2), decltype(aT1 & aT2)>, 151 "binary ops should have the same result type"); 152 static_assert(std::is_same_v<decltype(aT1 | aT2), decltype(aT1 ^ aT2)>, 153 "binary ops should have the same result type"); 154 155 static_assert(o == '|' || o == '&' || o == '^', 156 "unexpected operator character"); 157 158 return o == '|' ? aT1 | aT2 : o == '&' ? aT1 & aT2 : aT1 ^ aT2; 159 } 160 161 // OpAssign wraps a bitwise binary operator, passed as a char template 162 // parameter, and applies the corresponding compound-assignment operator to its 163 // arguments (aT1, aT2). For example, 164 // 165 // OpAssign<'|'>(aT1, aT2) 166 // 167 // is the same as 168 // 169 // aT1 |= aT2. 170 // 171 template <char o, typename T1, typename T2> 172 T1& OpAssign(T1& aT1, const T2& aT2) { 173 static_assert(o == '|' || o == '&' || o == '^', 174 "unexpected operator character"); 175 176 switch (o) { 177 case '|': 178 return aT1 |= aT2; 179 case '&': 180 return aT1 &= aT2; 181 case '^': 182 return aT1 ^= aT2; 183 default: 184 MOZ_CRASH(); 185 } 186 } 187 188 // Tests a single binary bitwise operator, using a single set of three operands. 189 // The operations tested are: 190 // 191 // result = aT1 Op aT2; 192 // result Op= aT3; 193 // 194 // Where Op is the operator specified by the char template parameter 'o' and 195 // can be any of '|', '&', '^'. 196 // 197 // Note that the operands aT1, aT2, aT3 are intentionally passed with free 198 // types (separate template parameters for each) because their type may 199 // actually be different from TypedEnum: 200 // 201 // 1) Their type could be CastableTypedEnumResult<TypedEnum> if they are 202 // the result of a bitwise operation themselves; 203 // 2) In the non-c++11 legacy path, the type of enum values is also 204 // different from TypedEnum. 205 // 206 template <typename TypedEnum, char o, typename T1, typename T2, typename T3> 207 void TestBinOp(const T1& aT1, const T2& aT2, const T3& aT3) { 208 typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type 209 UnsignedIntegerType; 210 211 // Part 1: 212 // Test the bitwise binary operator i.e. 213 // result = aT1 Op aT2; 214 auto result = Op<o>(aT1, aT2); 215 216 typedef decltype(result) ResultType; 217 218 RequireLiteralType<ResultType>(); 219 TestNonConvertibilityForOneType<ResultType>(); 220 221 UnsignedIntegerType unsignedIntegerResult = 222 Op<o>(UnsignedIntegerType(aT1), UnsignedIntegerType(aT2)); 223 224 MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); 225 MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); 226 MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); 227 MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); 228 MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); 229 230 // Part 2: 231 // Test the compound-assignment operator, i.e. 232 // result Op= aT3; 233 TypedEnum newResult = result; 234 OpAssign<o>(newResult, aT3); 235 UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult; 236 OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(aT3)); 237 MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult); 238 239 // Part 3: 240 // Test additional boolean operators that we unfortunately had to add to 241 // CastableTypedEnumResult at some point to please some compiler, 242 // even though bool convertibility should have been enough. 243 MOZ_RELEASE_ASSERT(result == TypedEnum(result)); 244 MOZ_RELEASE_ASSERT(!(result != TypedEnum(result))); 245 MOZ_RELEASE_ASSERT((result && true) == bool(result)); 246 MOZ_RELEASE_ASSERT((result && false) == false); 247 MOZ_RELEASE_ASSERT((true && result) == bool(result)); 248 MOZ_RELEASE_ASSERT((false && result && false) == false); 249 MOZ_RELEASE_ASSERT((result || false) == bool(result)); 250 MOZ_RELEASE_ASSERT((result || true) == true); 251 MOZ_RELEASE_ASSERT((false || result) == bool(result)); 252 MOZ_RELEASE_ASSERT((true || result) == true); 253 254 // Part 4: 255 // Test short-circuit evaluation. 256 auto Explode = [] { 257 // This function should never be called. Return an arbitrary value. 258 MOZ_RELEASE_ASSERT(false); 259 return false; 260 }; 261 if (result) { 262 MOZ_RELEASE_ASSERT(result || Explode()); 263 MOZ_RELEASE_ASSERT(!(!result && Explode())); 264 } else { 265 MOZ_RELEASE_ASSERT(!(result && Explode())); 266 MOZ_RELEASE_ASSERT(!result || Explode()); 267 } 268 } 269 270 // Similar to TestBinOp but testing the unary ~ operator. 271 template <typename TypedEnum, typename T> 272 void TestTilde(const T& aT) { 273 typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type 274 UnsignedIntegerType; 275 276 auto result = ~aT; 277 278 typedef decltype(result) ResultType; 279 280 RequireLiteralType<ResultType>(); 281 TestNonConvertibilityForOneType<ResultType>(); 282 283 UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(aT)); 284 285 MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); 286 MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); 287 MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); 288 MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); 289 MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); 290 } 291 292 // Helper dispatching a given triple of operands to all operator-specific 293 // testing functions. 294 template <typename TypedEnum, typename T1, typename T2, typename T3> 295 void TestAllOpsForGivenOperands(const T1& aT1, const T2& aT2, const T3& aT3) { 296 TestBinOp<TypedEnum, '|'>(aT1, aT2, aT3); 297 TestBinOp<TypedEnum, '&'>(aT1, aT2, aT3); 298 TestBinOp<TypedEnum, '^'>(aT1, aT2, aT3); 299 TestTilde<TypedEnum>(aT1); 300 } 301 302 // Helper building various triples of operands using a given operator, 303 // and testing all operators with them. 304 template <typename TypedEnum, char o> 305 void TestAllOpsForOperandsBuiltUsingGivenOp() { 306 // The type of enum values like TypedEnum::A may be different from 307 // TypedEnum. That is the case in the legacy non-C++11 path. We want to 308 // ensure good test coverage even when these two types are distinct. 309 // To that effect, we have both 'auto' typed variables, preserving the 310 // original type of enum values, and 'plain' typed variables, that 311 // are plain TypedEnum's. 312 313 const TypedEnum a_plain = TypedEnum::A; 314 const TypedEnum b_plain = TypedEnum::B; 315 const TypedEnum c_plain = TypedEnum::C; 316 317 auto a_auto = TypedEnum::A; 318 auto b_auto = TypedEnum::B; 319 auto c_auto = TypedEnum::C; 320 321 auto ab_plain = Op<o>(a_plain, b_plain); 322 auto bc_plain = Op<o>(b_plain, c_plain); 323 auto ab_auto = Op<o>(a_auto, b_auto); 324 auto bc_auto = Op<o>(b_auto, c_auto); 325 326 // On each row below, we pass a triple of operands. Keep in mind that this 327 // is going to be received as (aT1, aT2, aT3) and the actual tests performed 328 // will be of the form 329 // 330 // result = aT1 Op aT2; 331 // result Op= aT3; 332 // 333 // For this reason, we carefully ensure that the values of (aT1, aT2) 334 // systematically cover all types of such pairs; to limit complexity, 335 // we are not so careful with aT3, and we just try to pass aT3's 336 // that may lead to nontrivial bitwise operations. 337 TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_plain, c_plain); 338 TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_plain, b_auto); 339 TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain, a_plain); 340 TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto); 341 342 TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_auto, c_plain); 343 TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_auto, b_auto); 344 TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto, a_plain); 345 TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto, a_auto); 346 347 TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_plain, c_plain); 348 TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_plain, b_auto); 349 TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_plain, a_plain); 350 TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_plain, a_auto); 351 352 TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_auto, c_plain); 353 TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_auto, b_auto); 354 TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_auto, a_plain); 355 TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_auto, a_auto); 356 } 357 358 // Tests all bitwise operations on a given TypedEnum bitfield. 359 template <typename TypedEnum> 360 void TestTypedEnumBitField() { 361 TestTypedEnumBasics<TypedEnum>(); 362 363 TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>(); 364 TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>(); 365 TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>(); 366 } 367 368 // Checks that enum bitwise expressions have the same non-convertibility 369 // properties as c++11 enum classes do, i.e. not implicitly convertible to 370 // anything (though *explicitly* convertible). 371 void TestNoConversionsBetweenUnrelatedTypes() { 372 // Two typed enum classes having the same underlying integer type, to ensure 373 // that we would catch bugs accidentally allowing conversions in that case. 374 typedef CharEnumBitField T1; 375 typedef Nested::CharEnumBitField T2; 376 377 static_assert(!std::is_convertible_v<T1, T2>, "should not be convertible"); 378 static_assert(!std::is_convertible_v<T1, decltype(T2::A)>, 379 "should not be convertible"); 380 static_assert(!std::is_convertible_v<T1, decltype(T2::A | T2::B)>, 381 "should not be convertible"); 382 383 static_assert(!std::is_convertible_v<decltype(T1::A), T2>, 384 "should not be convertible"); 385 static_assert(!std::is_convertible_v<decltype(T1::A), decltype(T2::A)>, 386 "should not be convertible"); 387 static_assert( 388 !std::is_convertible_v<decltype(T1::A), decltype(T2::A | T2::B)>, 389 "should not be convertible"); 390 391 static_assert(!std::is_convertible_v<decltype(T1::A | T1::B), T2>, 392 "should not be convertible"); 393 static_assert( 394 !std::is_convertible_v<decltype(T1::A | T1::B), decltype(T2::A)>, 395 "should not be convertible"); 396 static_assert( 397 !std::is_convertible_v<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>, 398 "should not be convertible"); 399 } 400 401 enum class Int8EnumWithHighBits : int8_t { A = 0x20, B = 0x40 }; 402 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits) 403 404 enum class Uint8EnumWithHighBits : uint8_t { A = 0x40, B = 0x80 }; 405 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits) 406 407 enum class Int16EnumWithHighBits : int16_t { A = 0x2000, B = 0x4000 }; 408 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits) 409 410 enum class Uint16EnumWithHighBits : uint16_t { A = 0x4000, B = 0x8000 }; 411 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits) 412 413 enum class Int32EnumWithHighBits : int32_t { A = 0x20000000, B = 0x40000000 }; 414 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits) 415 416 enum class Uint32EnumWithHighBits : uint32_t { 417 A = 0x40000000u, 418 B = 0x80000000u 419 }; 420 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits) 421 422 enum class Int64EnumWithHighBits : int64_t { 423 A = 0x2000000000000000ll, 424 B = 0x4000000000000000ll 425 }; 426 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits) 427 428 enum class Uint64EnumWithHighBits : uint64_t { 429 A = 0x4000000000000000ull, 430 B = 0x8000000000000000ull 431 }; 432 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits) 433 434 // Checks that we don't accidentally truncate high bits by coercing to the wrong 435 // integer type internally when implementing bitwise ops. 436 template <typename EnumType, typename IntType> 437 void TestIsNotTruncated() { 438 EnumType a = EnumType::A; 439 EnumType b = EnumType::B; 440 MOZ_RELEASE_ASSERT(IntType(a)); 441 MOZ_RELEASE_ASSERT(IntType(b)); 442 MOZ_RELEASE_ASSERT(a | EnumType::B); 443 MOZ_RELEASE_ASSERT(a | b); 444 MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B); 445 EnumType c = EnumType::A | EnumType::B; 446 MOZ_RELEASE_ASSERT(IntType(c)); 447 MOZ_RELEASE_ASSERT(c & c); 448 MOZ_RELEASE_ASSERT(c | c); 449 MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B)); 450 MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B)); 451 MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B)); 452 MOZ_RELEASE_ASSERT(c & EnumType::A); 453 MOZ_RELEASE_ASSERT(c & EnumType::B); 454 EnumType d = EnumType::A; 455 d |= EnumType::B; 456 MOZ_RELEASE_ASSERT(d == c); 457 } 458 459 int main() { 460 TestTypedEnumBasics<AutoEnum>(); 461 TestTypedEnumBasics<CharEnum>(); 462 TestTypedEnumBasics<Nested::AutoEnum>(); 463 TestTypedEnumBasics<Nested::CharEnum>(); 464 465 TestTypedEnumBitField<AutoEnumBitField>(); 466 TestTypedEnumBitField<CharEnumBitField>(); 467 TestTypedEnumBitField<Nested::AutoEnumBitField>(); 468 TestTypedEnumBitField<Nested::CharEnumBitField>(); 469 470 TestTypedEnumBitField<BitFieldFor_uint8_t>(); 471 TestTypedEnumBitField<BitFieldFor_int8_t>(); 472 TestTypedEnumBitField<BitFieldFor_uint16_t>(); 473 TestTypedEnumBitField<BitFieldFor_int16_t>(); 474 TestTypedEnumBitField<BitFieldFor_uint32_t>(); 475 TestTypedEnumBitField<BitFieldFor_int32_t>(); 476 TestTypedEnumBitField<BitFieldFor_uint64_t>(); 477 TestTypedEnumBitField<BitFieldFor_int64_t>(); 478 TestTypedEnumBitField<BitFieldFor_char>(); 479 TestTypedEnumBitField<BitFieldFor_signed_char>(); 480 TestTypedEnumBitField<BitFieldFor_unsigned_char>(); 481 TestTypedEnumBitField<BitFieldFor_short>(); 482 TestTypedEnumBitField<BitFieldFor_unsigned_short>(); 483 TestTypedEnumBitField<BitFieldFor_int>(); 484 TestTypedEnumBitField<BitFieldFor_unsigned_int>(); 485 TestTypedEnumBitField<BitFieldFor_long>(); 486 TestTypedEnumBitField<BitFieldFor_unsigned_long>(); 487 TestTypedEnumBitField<BitFieldFor_long_long>(); 488 TestTypedEnumBitField<BitFieldFor_unsigned_long_long>(); 489 490 TestNoConversionsBetweenUnrelatedTypes(); 491 492 TestIsNotTruncated<Int8EnumWithHighBits, int8_t>(); 493 TestIsNotTruncated<Int16EnumWithHighBits, int16_t>(); 494 TestIsNotTruncated<Int32EnumWithHighBits, int32_t>(); 495 TestIsNotTruncated<Int64EnumWithHighBits, int64_t>(); 496 TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>(); 497 TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>(); 498 TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>(); 499 TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>(); 500 501 return 0; 502 }