1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/tests/TestTypedEnum.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,570 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "mozilla/Assertions.h" 1.9 +#include "mozilla/Attributes.h" 1.10 +#include "mozilla/TypedEnum.h" 1.11 +#include "mozilla/TypedEnumBits.h" 1.12 + 1.13 +#include <stdint.h> 1.14 + 1.15 +// A rough feature check for is_literal_type. Not very carefully checked. 1.16 +// Feel free to amend as needed. 1.17 +// We leave ANDROID out because it's using stlport which doesn't have std::is_literal_type. 1.18 +#if __cplusplus >= 201103L && !defined(ANDROID) 1.19 +# if defined(__clang__) 1.20 + /* 1.21 + * Per Clang documentation, "Note that marketing version numbers should not 1.22 + * be used to check for language features, as different vendors use different 1.23 + * numbering schemes. Instead, use the feature checking macros." 1.24 + */ 1.25 +# ifndef __has_extension 1.26 +# define __has_extension __has_feature /* compatibility, for older versions of clang */ 1.27 +# endif 1.28 +# if __has_extension(is_literal) && __has_include(<type_traits>) 1.29 +# define MOZ_HAVE_IS_LITERAL 1.30 +# endif 1.31 +# elif defined(__GNUC__) 1.32 +# if defined(__GXX_EXPERIMENTAL_CXX0X__) 1.33 +# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) 1.34 +# define MOZ_HAVE_IS_LITERAL 1.35 +# endif 1.36 +# endif 1.37 +# elif defined(_MSC_VER) 1.38 +# if _MSC_VER >= 1700 1.39 +# define MOZ_HAVE_IS_LITERAL 1.40 +# endif 1.41 +# endif 1.42 +#endif 1.43 + 1.44 +#ifdef MOZ_HAVE_IS_LITERAL 1.45 +#include <type_traits> 1.46 +template<typename T> 1.47 +void 1.48 +RequireLiteralType() 1.49 +{ 1.50 + static_assert(std::is_literal_type<T>::value, "Expected a literal type"); 1.51 +} 1.52 +#else // not MOZ_HAVE_IS_LITERAL 1.53 +template<typename T> 1.54 +void 1.55 +RequireLiteralType() 1.56 +{ 1.57 +} 1.58 +#endif 1.59 + 1.60 +template<typename T> 1.61 +void 1.62 +RequireLiteralType(const T&) 1.63 +{ 1.64 + RequireLiteralType<T>(); 1.65 +} 1.66 + 1.67 +MOZ_BEGIN_ENUM_CLASS(AutoEnum) 1.68 + A, 1.69 + B = -3, 1.70 + C 1.71 +MOZ_END_ENUM_CLASS(AutoEnum) 1.72 + 1.73 +MOZ_BEGIN_ENUM_CLASS(CharEnum, char) 1.74 + A, 1.75 + B = 3, 1.76 + C 1.77 +MOZ_END_ENUM_CLASS(CharEnum) 1.78 + 1.79 +MOZ_BEGIN_ENUM_CLASS(AutoEnumBitField) 1.80 + A = 0x10, 1.81 + B = 0x20, 1.82 + C 1.83 +MOZ_END_ENUM_CLASS(AutoEnumBitField) 1.84 + 1.85 +MOZ_BEGIN_ENUM_CLASS(CharEnumBitField, char) 1.86 + A = 0x10, 1.87 + B, 1.88 + C = 0x40 1.89 +MOZ_END_ENUM_CLASS(CharEnumBitField) 1.90 + 1.91 +struct Nested 1.92 +{ 1.93 + MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnum) 1.94 + A, 1.95 + B, 1.96 + C = -1 1.97 + MOZ_END_NESTED_ENUM_CLASS(AutoEnum) 1.98 + 1.99 + MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnum, char) 1.100 + A = 4, 1.101 + B, 1.102 + C = 1 1.103 + MOZ_END_NESTED_ENUM_CLASS(CharEnum) 1.104 + 1.105 + MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnumBitField) 1.106 + A, 1.107 + B = 0x20, 1.108 + C 1.109 + MOZ_END_NESTED_ENUM_CLASS(AutoEnumBitField) 1.110 + 1.111 + MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnumBitField, char) 1.112 + A = 1, 1.113 + B = 1, 1.114 + C = 1 1.115 + MOZ_END_NESTED_ENUM_CLASS(CharEnumBitField) 1.116 +}; 1.117 + 1.118 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField) 1.119 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField) 1.120 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField) 1.121 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField) 1.122 + 1.123 +#define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \ 1.124 + MOZ_BEGIN_ENUM_CLASS(BitFieldFor_##IntType, IntType) \ 1.125 + A = 1, \ 1.126 + B = 2, \ 1.127 + C = 4, \ 1.128 + MOZ_END_ENUM_CLASS(BitFieldFor_##IntType) \ 1.129 + MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType) 1.130 + 1.131 +MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t) 1.132 +MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t) 1.133 +MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t) 1.134 +MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t) 1.135 +MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t) 1.136 +MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t) 1.137 +MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t) 1.138 +MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t) 1.139 +MAKE_STANDARD_BITFIELD_FOR_TYPE(char) 1.140 +typedef signed char signed_char; 1.141 +MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char) 1.142 +typedef unsigned char unsigned_char; 1.143 +MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char) 1.144 +MAKE_STANDARD_BITFIELD_FOR_TYPE(short) 1.145 +typedef unsigned short unsigned_short; 1.146 +MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short) 1.147 +MAKE_STANDARD_BITFIELD_FOR_TYPE(int) 1.148 +typedef unsigned int unsigned_int; 1.149 +MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int) 1.150 +MAKE_STANDARD_BITFIELD_FOR_TYPE(long) 1.151 +typedef unsigned long unsigned_long; 1.152 +MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long) 1.153 +typedef long long long_long; 1.154 +MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long) 1.155 +typedef unsigned long long unsigned_long_long; 1.156 +MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long) 1.157 + 1.158 +#undef MAKE_STANDARD_BITFIELD_FOR_TYPE 1.159 + 1.160 +template<typename T> 1.161 +void 1.162 +TestNonConvertibilityForOneType() 1.163 +{ 1.164 + using mozilla::IsConvertible; 1.165 + 1.166 +#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) && defined(MOZ_HAVE_EXPLICIT_CONVERSION) 1.167 + static_assert(!IsConvertible<T, bool>::value, "should not be convertible"); 1.168 + static_assert(!IsConvertible<T, int>::value, "should not be convertible"); 1.169 + static_assert(!IsConvertible<T, uint64_t>::value, "should not be convertible"); 1.170 +#endif 1.171 + 1.172 + static_assert(!IsConvertible<bool, T>::value, "should not be convertible"); 1.173 + static_assert(!IsConvertible<int, T>::value, "should not be convertible"); 1.174 + static_assert(!IsConvertible<uint64_t, T>::value, "should not be convertible"); 1.175 +} 1.176 + 1.177 +template<typename TypedEnum> 1.178 +void 1.179 +TestTypedEnumBasics() 1.180 +{ 1.181 + const TypedEnum a = TypedEnum::A; 1.182 + int unused = int(a); 1.183 + (void) unused; 1.184 + RequireLiteralType(TypedEnum::A); 1.185 + RequireLiteralType(a); 1.186 + TestNonConvertibilityForOneType<TypedEnum>(); 1.187 +} 1.188 + 1.189 +// Op wraps a bitwise binary operator, passed as a char template parameter, 1.190 +// and applies it to its arguments (t1, t2). For example, 1.191 +// 1.192 +// Op<'|'>(t1, t2) 1.193 +// 1.194 +// is the same as 1.195 +// 1.196 +// t1 | t2. 1.197 +// 1.198 +template<char o, typename T1, typename T2> 1.199 +auto Op(const T1& t1, const T2& t2) 1.200 + -> decltype(t1 | t2) // See the static_assert's below --- the return type 1.201 + // depends solely on the operands type, not on the 1.202 + // choice of operation. 1.203 +{ 1.204 + using mozilla::IsSame; 1.205 + static_assert(IsSame<decltype(t1 | t2), decltype(t1 & t2)>::value, 1.206 + "binary ops should have the same result type"); 1.207 + static_assert(IsSame<decltype(t1 | t2), decltype(t1 ^ t2)>::value, 1.208 + "binary ops should have the same result type"); 1.209 + 1.210 + static_assert(o == '|' || 1.211 + o == '&' || 1.212 + o == '^', "unexpected operator character"); 1.213 + 1.214 + return o == '|' ? t1 | t2 1.215 + : o == '&' ? t1 & t2 1.216 + : t1 ^ t2; 1.217 +} 1.218 + 1.219 +// OpAssign wraps a bitwise binary operator, passed as a char template 1.220 +// parameter, and applies the corresponding compound-assignment operator to its 1.221 +// arguments (t1, t2). For example, 1.222 +// 1.223 +// OpAssign<'|'>(t1, t2) 1.224 +// 1.225 +// is the same as 1.226 +// 1.227 +// t1 |= t2. 1.228 +// 1.229 +template<char o, typename T1, typename T2> 1.230 +T1& OpAssign(T1& t1, const T2& t2) 1.231 +{ 1.232 + static_assert(o == '|' || 1.233 + o == '&' || 1.234 + o == '^', "unexpected operator character"); 1.235 + 1.236 + switch (o) { 1.237 + case '|': return t1 |= t2; 1.238 + case '&': return t1 &= t2; 1.239 + case '^': return t1 ^= t2; 1.240 + default: MOZ_CRASH(); 1.241 + } 1.242 +} 1.243 + 1.244 +// Tests a single binary bitwise operator, using a single set of three operands. 1.245 +// The operations tested are: 1.246 +// 1.247 +// result = t1 Op t2; 1.248 +// result Op= t3; 1.249 +// 1.250 +// Where Op is the operator specified by the char template parameter 'o' and can 1.251 +// be any of '|', '&', '^'. 1.252 +// 1.253 +// Note that the operands t1, t2, t3 are intentionally passed with free types 1.254 +// (separate template parameters for each) because their type may actually be 1.255 +// different from TypedEnum: 1.256 +// 1) Their type could be CastableTypedEnumResult<TypedEnum> if they are 1.257 +// the result of a bitwise operation themselves; 1.258 +// 2) In the non-c++11 legacy path, the type of enum values is also 1.259 +// different from TypedEnum. 1.260 +// 1.261 +template<typename TypedEnum, char o, typename T1, typename T2, typename T3> 1.262 +void TestBinOp(const T1& t1, const T2& t2, const T3& t3) 1.263 +{ 1.264 + typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type 1.265 + UnsignedIntegerType; 1.266 + 1.267 + // Part 1: 1.268 + // Test the bitwise binary operator i.e. 1.269 + // result = t1 Op t2; 1.270 + auto result = Op<o>(t1, t2); 1.271 + 1.272 + typedef decltype(result) ResultType; 1.273 + 1.274 + RequireLiteralType<ResultType>(); 1.275 + TestNonConvertibilityForOneType<ResultType>(); 1.276 + 1.277 + UnsignedIntegerType unsignedIntegerResult 1.278 + = Op<o>(UnsignedIntegerType(t1), UnsignedIntegerType(t2)); 1.279 + 1.280 + MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); 1.281 + MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); 1.282 + MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); 1.283 + MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); 1.284 + MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); 1.285 + 1.286 + // Part 2: 1.287 + // Test the compound-assignment operator, i.e. 1.288 + // result Op= t3; 1.289 + TypedEnum newResult = result; 1.290 + OpAssign<o>(newResult, t3); 1.291 + UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult; 1.292 + OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(t3)); 1.293 + MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult); 1.294 + 1.295 + // Part 3: 1.296 + // Test additional boolean operators that we unfortunately had to add to 1.297 + // CastableTypedEnumResult at some point to please some compiler, 1.298 + // even though bool convertibility should have been enough. 1.299 + MOZ_RELEASE_ASSERT(result == TypedEnum(result)); 1.300 + MOZ_RELEASE_ASSERT(!(result != TypedEnum(result))); 1.301 + MOZ_RELEASE_ASSERT((result && true) == bool(result)); 1.302 + MOZ_RELEASE_ASSERT((result && false) == false); 1.303 + MOZ_RELEASE_ASSERT((true && result) == bool(result)); 1.304 + MOZ_RELEASE_ASSERT((false && result && false) == false); 1.305 + MOZ_RELEASE_ASSERT((result || false) == bool(result)); 1.306 + MOZ_RELEASE_ASSERT((result || true) == true); 1.307 + MOZ_RELEASE_ASSERT((false || result) == bool(result)); 1.308 + MOZ_RELEASE_ASSERT((true || result) == true); 1.309 +} 1.310 + 1.311 +// Similar to TestBinOp but testing the unary ~ operator. 1.312 +template<typename TypedEnum, typename T> 1.313 +void TestTilde(const T& t) 1.314 +{ 1.315 + typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type 1.316 + UnsignedIntegerType; 1.317 + 1.318 + auto result = ~t; 1.319 + 1.320 + typedef decltype(result) ResultType; 1.321 + 1.322 + RequireLiteralType<ResultType>(); 1.323 + TestNonConvertibilityForOneType<ResultType>(); 1.324 + 1.325 + UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(t)); 1.326 + 1.327 + MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); 1.328 + MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); 1.329 + MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); 1.330 + MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); 1.331 + MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); 1.332 +} 1.333 + 1.334 +// Helper dispatching a given triple of operands to all operator-specific 1.335 +// testing functions. 1.336 +template<typename TypedEnum, typename T1, typename T2, typename T3> 1.337 +void TestAllOpsForGivenOperands(const T1& t1, const T2& t2, const T3& t3) 1.338 +{ 1.339 + TestBinOp<TypedEnum, '|'>(t1, t2, t3); 1.340 + TestBinOp<TypedEnum, '&'>(t1, t2, t3); 1.341 + TestBinOp<TypedEnum, '^'>(t1, t2, t3); 1.342 + TestTilde<TypedEnum>(t1); 1.343 +} 1.344 + 1.345 +// Helper building various triples of operands using a given operator, 1.346 +// and testing all operators with them. 1.347 +template<typename TypedEnum, char o> 1.348 +void TestAllOpsForOperandsBuiltUsingGivenOp() 1.349 +{ 1.350 + // The type of enum values like TypedEnum::A may be different from 1.351 + // TypedEnum. That is the case in the legacy non-C++11 path. We want to 1.352 + // ensure good test coverage even when these two types are distinct. 1.353 + // To that effect, we have both 'auto' typed variables, preserving the 1.354 + // original type of enum values, and 'plain' typed variables, that 1.355 + // are plain TypedEnum's. 1.356 + 1.357 + const TypedEnum a_plain = TypedEnum::A; 1.358 + const TypedEnum b_plain = TypedEnum::B; 1.359 + const TypedEnum c_plain = TypedEnum::C; 1.360 + 1.361 + auto a_auto = TypedEnum::A; 1.362 + auto b_auto = TypedEnum::B; 1.363 + auto c_auto = TypedEnum::C; 1.364 + 1.365 + auto ab_plain = Op<o>(a_plain, b_plain); 1.366 + auto bc_plain = Op<o>(b_plain, c_plain); 1.367 + auto ab_auto = Op<o>(a_auto, b_auto); 1.368 + auto bc_auto = Op<o>(b_auto, c_auto); 1.369 + 1.370 + // On each row below, we pass a triple of operands. Keep in mind that this 1.371 + // is going to be received as (t1, t2, t3) and the actual tests performed 1.372 + // will be of the form 1.373 + // 1.374 + // result = t1 Op t2; 1.375 + // result Op= t3; 1.376 + // 1.377 + // For this reason, we carefully ensure that the values of (t1, t2) 1.378 + // systematically cover all types of such pairs; to limit complexity, 1.379 + // we are not so careful with t3, and we just try to pass t3's 1.380 + // that may lead to nontrivial bitwise operations. 1.381 + TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_plain, c_plain); 1.382 + TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_plain, b_auto); 1.383 + TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain, a_plain); 1.384 + TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto); 1.385 + 1.386 + TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_auto, c_plain); 1.387 + TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_auto, b_auto); 1.388 + TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto, a_plain); 1.389 + TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto, a_auto); 1.390 + 1.391 + TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_plain, c_plain); 1.392 + TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_plain, b_auto); 1.393 + TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_plain, a_plain); 1.394 + TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_plain, a_auto); 1.395 + 1.396 + TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_auto, c_plain); 1.397 + TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_auto, b_auto); 1.398 + TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_auto, a_plain); 1.399 + TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_auto, a_auto); 1.400 +} 1.401 + 1.402 +// Tests all bitwise operations on a given TypedEnum bitfield. 1.403 +template<typename TypedEnum> 1.404 +void 1.405 +TestTypedEnumBitField() 1.406 +{ 1.407 + TestTypedEnumBasics<TypedEnum>(); 1.408 + 1.409 + TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>(); 1.410 + TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>(); 1.411 + TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>(); 1.412 +} 1.413 + 1.414 +// Checks that enum bitwise expressions have the same non-convertibility properties as 1.415 +// c++11 enum classes do, i.e. not implicitly convertible to anything 1.416 +// (though *explicitly* convertible). 1.417 +void TestNoConversionsBetweenUnrelatedTypes() 1.418 +{ 1.419 + using mozilla::IsConvertible; 1.420 + 1.421 + // Two typed enum classes having the same underlying integer type, to ensure that 1.422 + // we would catch bugs accidentally allowing conversions in that case. 1.423 + typedef CharEnumBitField T1; 1.424 + typedef Nested::CharEnumBitField T2; 1.425 + 1.426 + static_assert(!IsConvertible<T1, T2>::value, 1.427 + "should not be convertible"); 1.428 + static_assert(!IsConvertible<T1, decltype(T2::A)>::value, 1.429 + "should not be convertible"); 1.430 + static_assert(!IsConvertible<T1, decltype(T2::A | T2::B)>::value, 1.431 + "should not be convertible"); 1.432 + 1.433 + static_assert(!IsConvertible<decltype(T1::A), T2>::value, 1.434 + "should not be convertible"); 1.435 + static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A)>::value, 1.436 + "should not be convertible"); 1.437 + static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A | T2::B)>::value, 1.438 + "should not be convertible"); 1.439 + 1.440 + // The following are #ifdef MOZ_HAVE_EXPLICIT_CONVERSION because 1.441 + // without support for explicit conversion operators, we can't easily have these 1.442 + // bad conversions completely removed. They still do fail to compile in practice, 1.443 + // but not in a way that we can static_assert on. 1.444 +#ifdef MOZ_HAVE_EXPLICIT_CONVERSION 1.445 + static_assert(!IsConvertible<decltype(T1::A | T1::B), T2>::value, 1.446 + "should not be convertible"); 1.447 + static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A)>::value, 1.448 + "should not be convertible"); 1.449 + static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>::value, 1.450 + "should not be convertible"); 1.451 +#endif 1.452 +} 1.453 + 1.454 +MOZ_BEGIN_ENUM_CLASS(Int8EnumWithHighBits, int8_t) 1.455 + A = 0x20, 1.456 + B = 0x40 1.457 +MOZ_END_ENUM_CLASS(Int8EnumWithHighBits) 1.458 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits) 1.459 + 1.460 +MOZ_BEGIN_ENUM_CLASS(Uint8EnumWithHighBits, uint8_t) 1.461 + A = 0x40, 1.462 + B = 0x80 1.463 +MOZ_END_ENUM_CLASS(Uint8EnumWithHighBits) 1.464 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits) 1.465 + 1.466 +MOZ_BEGIN_ENUM_CLASS(Int16EnumWithHighBits, int16_t) 1.467 + A = 0x2000, 1.468 + B = 0x4000 1.469 +MOZ_END_ENUM_CLASS(Int16EnumWithHighBits) 1.470 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits) 1.471 + 1.472 +MOZ_BEGIN_ENUM_CLASS(Uint16EnumWithHighBits, uint16_t) 1.473 + A = 0x4000, 1.474 + B = 0x8000 1.475 +MOZ_END_ENUM_CLASS(Uint16EnumWithHighBits) 1.476 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits) 1.477 + 1.478 +MOZ_BEGIN_ENUM_CLASS(Int32EnumWithHighBits, int32_t) 1.479 + A = 0x20000000, 1.480 + B = 0x40000000 1.481 +MOZ_END_ENUM_CLASS(Int32EnumWithHighBits) 1.482 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits) 1.483 + 1.484 +MOZ_BEGIN_ENUM_CLASS(Uint32EnumWithHighBits, uint32_t) 1.485 + A = 0x40000000u, 1.486 + B = 0x80000000u 1.487 +MOZ_END_ENUM_CLASS(Uint32EnumWithHighBits) 1.488 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits) 1.489 + 1.490 +MOZ_BEGIN_ENUM_CLASS(Int64EnumWithHighBits, int64_t) 1.491 + A = 0x2000000000000000ll, 1.492 + B = 0x4000000000000000ll 1.493 +MOZ_END_ENUM_CLASS(Int64EnumWithHighBits) 1.494 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits) 1.495 + 1.496 +MOZ_BEGIN_ENUM_CLASS(Uint64EnumWithHighBits, uint64_t) 1.497 + A = 0x4000000000000000ull, 1.498 + B = 0x8000000000000000ull 1.499 +MOZ_END_ENUM_CLASS(Uint64EnumWithHighBits) 1.500 +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits) 1.501 + 1.502 +// Checks that we don't accidentally truncate high bits by coercing to the wrong 1.503 +// integer type internally when implementing bitwise ops. 1.504 +template<typename EnumType, typename IntType> 1.505 +void TestIsNotTruncated() 1.506 +{ 1.507 + EnumType a = EnumType::A; 1.508 + EnumType b = EnumType::B; 1.509 + MOZ_RELEASE_ASSERT(IntType(a)); 1.510 + MOZ_RELEASE_ASSERT(IntType(b)); 1.511 + MOZ_RELEASE_ASSERT(a | EnumType::B); 1.512 + MOZ_RELEASE_ASSERT(a | b); 1.513 + MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B); 1.514 + EnumType c = EnumType::A | EnumType::B; 1.515 + MOZ_RELEASE_ASSERT(IntType(c)); 1.516 + MOZ_RELEASE_ASSERT(c & c); 1.517 + MOZ_RELEASE_ASSERT(c | c); 1.518 + MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B)); 1.519 + MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B)); 1.520 + MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B)); 1.521 + MOZ_RELEASE_ASSERT(c & EnumType::A); 1.522 + MOZ_RELEASE_ASSERT(c & EnumType::B); 1.523 + EnumType d = EnumType::A; 1.524 + d |= EnumType::B; 1.525 + MOZ_RELEASE_ASSERT(d == c); 1.526 +} 1.527 + 1.528 +int 1.529 +main() 1.530 +{ 1.531 + TestTypedEnumBasics<AutoEnum>(); 1.532 + TestTypedEnumBasics<CharEnum>(); 1.533 + TestTypedEnumBasics<Nested::AutoEnum>(); 1.534 + TestTypedEnumBasics<Nested::CharEnum>(); 1.535 + 1.536 + TestTypedEnumBitField<AutoEnumBitField>(); 1.537 + TestTypedEnumBitField<CharEnumBitField>(); 1.538 + TestTypedEnumBitField<Nested::AutoEnumBitField>(); 1.539 + TestTypedEnumBitField<Nested::CharEnumBitField>(); 1.540 + 1.541 + TestTypedEnumBitField<BitFieldFor_uint8_t>(); 1.542 + TestTypedEnumBitField<BitFieldFor_int8_t>(); 1.543 + TestTypedEnumBitField<BitFieldFor_uint16_t>(); 1.544 + TestTypedEnumBitField<BitFieldFor_int16_t>(); 1.545 + TestTypedEnumBitField<BitFieldFor_uint32_t>(); 1.546 + TestTypedEnumBitField<BitFieldFor_int32_t>(); 1.547 + TestTypedEnumBitField<BitFieldFor_uint64_t>(); 1.548 + TestTypedEnumBitField<BitFieldFor_int64_t>(); 1.549 + TestTypedEnumBitField<BitFieldFor_char>(); 1.550 + TestTypedEnumBitField<BitFieldFor_signed_char>(); 1.551 + TestTypedEnumBitField<BitFieldFor_unsigned_char>(); 1.552 + TestTypedEnumBitField<BitFieldFor_short>(); 1.553 + TestTypedEnumBitField<BitFieldFor_unsigned_short>(); 1.554 + TestTypedEnumBitField<BitFieldFor_int>(); 1.555 + TestTypedEnumBitField<BitFieldFor_unsigned_int>(); 1.556 + TestTypedEnumBitField<BitFieldFor_long>(); 1.557 + TestTypedEnumBitField<BitFieldFor_unsigned_long>(); 1.558 + TestTypedEnumBitField<BitFieldFor_long_long>(); 1.559 + TestTypedEnumBitField<BitFieldFor_unsigned_long_long>(); 1.560 + 1.561 + TestNoConversionsBetweenUnrelatedTypes(); 1.562 + 1.563 + TestIsNotTruncated<Int8EnumWithHighBits, int8_t>(); 1.564 + TestIsNotTruncated<Int16EnumWithHighBits, int16_t>(); 1.565 + TestIsNotTruncated<Int32EnumWithHighBits, int32_t>(); 1.566 + TestIsNotTruncated<Int64EnumWithHighBits, int64_t>(); 1.567 + TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>(); 1.568 + TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>(); 1.569 + TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>(); 1.570 + TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>(); 1.571 + 1.572 + return 0; 1.573 +}