michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/TypedEnum.h" michael@0: #include "mozilla/TypedEnumBits.h" michael@0: michael@0: #include michael@0: michael@0: // A rough feature check for is_literal_type. Not very carefully checked. michael@0: // Feel free to amend as needed. michael@0: // We leave ANDROID out because it's using stlport which doesn't have std::is_literal_type. michael@0: #if __cplusplus >= 201103L && !defined(ANDROID) michael@0: # if defined(__clang__) michael@0: /* michael@0: * Per Clang documentation, "Note that marketing version numbers should not michael@0: * be used to check for language features, as different vendors use different michael@0: * numbering schemes. Instead, use the feature checking macros." michael@0: */ michael@0: # ifndef __has_extension michael@0: # define __has_extension __has_feature /* compatibility, for older versions of clang */ michael@0: # endif michael@0: # if __has_extension(is_literal) && __has_include() michael@0: # define MOZ_HAVE_IS_LITERAL michael@0: # endif michael@0: # elif defined(__GNUC__) michael@0: # if defined(__GXX_EXPERIMENTAL_CXX0X__) michael@0: # if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) michael@0: # define MOZ_HAVE_IS_LITERAL michael@0: # endif michael@0: # endif michael@0: # elif defined(_MSC_VER) michael@0: # if _MSC_VER >= 1700 michael@0: # define MOZ_HAVE_IS_LITERAL michael@0: # endif michael@0: # endif michael@0: #endif michael@0: michael@0: #ifdef MOZ_HAVE_IS_LITERAL michael@0: #include michael@0: template michael@0: void michael@0: RequireLiteralType() michael@0: { michael@0: static_assert(std::is_literal_type::value, "Expected a literal type"); michael@0: } michael@0: #else // not MOZ_HAVE_IS_LITERAL michael@0: template michael@0: void michael@0: RequireLiteralType() michael@0: { michael@0: } michael@0: #endif michael@0: michael@0: template michael@0: void michael@0: RequireLiteralType(const T&) michael@0: { michael@0: RequireLiteralType(); michael@0: } michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(AutoEnum) michael@0: A, michael@0: B = -3, michael@0: C michael@0: MOZ_END_ENUM_CLASS(AutoEnum) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(CharEnum, char) michael@0: A, michael@0: B = 3, michael@0: C michael@0: MOZ_END_ENUM_CLASS(CharEnum) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(AutoEnumBitField) michael@0: A = 0x10, michael@0: B = 0x20, michael@0: C michael@0: MOZ_END_ENUM_CLASS(AutoEnumBitField) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(CharEnumBitField, char) michael@0: A = 0x10, michael@0: B, michael@0: C = 0x40 michael@0: MOZ_END_ENUM_CLASS(CharEnumBitField) michael@0: michael@0: struct Nested michael@0: { michael@0: MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnum) michael@0: A, michael@0: B, michael@0: C = -1 michael@0: MOZ_END_NESTED_ENUM_CLASS(AutoEnum) michael@0: michael@0: MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnum, char) michael@0: A = 4, michael@0: B, michael@0: C = 1 michael@0: MOZ_END_NESTED_ENUM_CLASS(CharEnum) michael@0: michael@0: MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnumBitField) michael@0: A, michael@0: B = 0x20, michael@0: C michael@0: MOZ_END_NESTED_ENUM_CLASS(AutoEnumBitField) michael@0: michael@0: MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnumBitField, char) michael@0: A = 1, michael@0: B = 1, michael@0: C = 1 michael@0: MOZ_END_NESTED_ENUM_CLASS(CharEnumBitField) michael@0: }; michael@0: michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField) michael@0: michael@0: #define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \ michael@0: MOZ_BEGIN_ENUM_CLASS(BitFieldFor_##IntType, IntType) \ michael@0: A = 1, \ michael@0: B = 2, \ michael@0: C = 4, \ michael@0: MOZ_END_ENUM_CLASS(BitFieldFor_##IntType) \ michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType) michael@0: michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(char) michael@0: typedef signed char signed_char; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char) michael@0: typedef unsigned char unsigned_char; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(short) michael@0: typedef unsigned short unsigned_short; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(int) michael@0: typedef unsigned int unsigned_int; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int) michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(long) michael@0: typedef unsigned long unsigned_long; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long) michael@0: typedef long long long_long; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long) michael@0: typedef unsigned long long unsigned_long_long; michael@0: MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long) michael@0: michael@0: #undef MAKE_STANDARD_BITFIELD_FOR_TYPE michael@0: michael@0: template michael@0: void michael@0: TestNonConvertibilityForOneType() michael@0: { michael@0: using mozilla::IsConvertible; michael@0: michael@0: #if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) && defined(MOZ_HAVE_EXPLICIT_CONVERSION) michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: #endif michael@0: michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: static_assert(!IsConvertible::value, "should not be convertible"); michael@0: } michael@0: michael@0: template michael@0: void michael@0: TestTypedEnumBasics() michael@0: { michael@0: const TypedEnum a = TypedEnum::A; michael@0: int unused = int(a); michael@0: (void) unused; michael@0: RequireLiteralType(TypedEnum::A); michael@0: RequireLiteralType(a); michael@0: TestNonConvertibilityForOneType(); michael@0: } michael@0: michael@0: // Op wraps a bitwise binary operator, passed as a char template parameter, michael@0: // and applies it to its arguments (t1, t2). For example, michael@0: // michael@0: // Op<'|'>(t1, t2) michael@0: // michael@0: // is the same as michael@0: // michael@0: // t1 | t2. michael@0: // michael@0: template michael@0: auto Op(const T1& t1, const T2& t2) michael@0: -> decltype(t1 | t2) // See the static_assert's below --- the return type michael@0: // depends solely on the operands type, not on the michael@0: // choice of operation. michael@0: { michael@0: using mozilla::IsSame; michael@0: static_assert(IsSame::value, michael@0: "binary ops should have the same result type"); michael@0: static_assert(IsSame::value, michael@0: "binary ops should have the same result type"); michael@0: michael@0: static_assert(o == '|' || michael@0: o == '&' || michael@0: o == '^', "unexpected operator character"); michael@0: michael@0: return o == '|' ? t1 | t2 michael@0: : o == '&' ? t1 & t2 michael@0: : t1 ^ t2; michael@0: } michael@0: michael@0: // OpAssign wraps a bitwise binary operator, passed as a char template michael@0: // parameter, and applies the corresponding compound-assignment operator to its michael@0: // arguments (t1, t2). For example, michael@0: // michael@0: // OpAssign<'|'>(t1, t2) michael@0: // michael@0: // is the same as michael@0: // michael@0: // t1 |= t2. michael@0: // michael@0: template michael@0: T1& OpAssign(T1& t1, const T2& t2) michael@0: { michael@0: static_assert(o == '|' || michael@0: o == '&' || michael@0: o == '^', "unexpected operator character"); michael@0: michael@0: switch (o) { michael@0: case '|': return t1 |= t2; michael@0: case '&': return t1 &= t2; michael@0: case '^': return t1 ^= t2; michael@0: default: MOZ_CRASH(); michael@0: } michael@0: } michael@0: michael@0: // Tests a single binary bitwise operator, using a single set of three operands. michael@0: // The operations tested are: michael@0: // michael@0: // result = t1 Op t2; michael@0: // result Op= t3; michael@0: // michael@0: // Where Op is the operator specified by the char template parameter 'o' and can michael@0: // be any of '|', '&', '^'. michael@0: // michael@0: // Note that the operands t1, t2, t3 are intentionally passed with free types michael@0: // (separate template parameters for each) because their type may actually be michael@0: // different from TypedEnum: michael@0: // 1) Their type could be CastableTypedEnumResult if they are michael@0: // the result of a bitwise operation themselves; michael@0: // 2) In the non-c++11 legacy path, the type of enum values is also michael@0: // different from TypedEnum. michael@0: // michael@0: template michael@0: void TestBinOp(const T1& t1, const T2& t2, const T3& t3) michael@0: { michael@0: typedef typename mozilla::detail::UnsignedIntegerTypeForEnum::Type michael@0: UnsignedIntegerType; michael@0: michael@0: // Part 1: michael@0: // Test the bitwise binary operator i.e. michael@0: // result = t1 Op t2; michael@0: auto result = Op(t1, t2); michael@0: michael@0: typedef decltype(result) ResultType; michael@0: michael@0: RequireLiteralType(); michael@0: TestNonConvertibilityForOneType(); michael@0: michael@0: UnsignedIntegerType unsignedIntegerResult michael@0: = Op(UnsignedIntegerType(t1), UnsignedIntegerType(t2)); michael@0: michael@0: MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); michael@0: MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); michael@0: MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); michael@0: MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); michael@0: MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); michael@0: michael@0: // Part 2: michael@0: // Test the compound-assignment operator, i.e. michael@0: // result Op= t3; michael@0: TypedEnum newResult = result; michael@0: OpAssign(newResult, t3); michael@0: UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult; michael@0: OpAssign(unsignedIntegerNewResult, UnsignedIntegerType(t3)); michael@0: MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult); michael@0: michael@0: // Part 3: michael@0: // Test additional boolean operators that we unfortunately had to add to michael@0: // CastableTypedEnumResult at some point to please some compiler, michael@0: // even though bool convertibility should have been enough. michael@0: MOZ_RELEASE_ASSERT(result == TypedEnum(result)); michael@0: MOZ_RELEASE_ASSERT(!(result != TypedEnum(result))); michael@0: MOZ_RELEASE_ASSERT((result && true) == bool(result)); michael@0: MOZ_RELEASE_ASSERT((result && false) == false); michael@0: MOZ_RELEASE_ASSERT((true && result) == bool(result)); michael@0: MOZ_RELEASE_ASSERT((false && result && false) == false); michael@0: MOZ_RELEASE_ASSERT((result || false) == bool(result)); michael@0: MOZ_RELEASE_ASSERT((result || true) == true); michael@0: MOZ_RELEASE_ASSERT((false || result) == bool(result)); michael@0: MOZ_RELEASE_ASSERT((true || result) == true); michael@0: } michael@0: michael@0: // Similar to TestBinOp but testing the unary ~ operator. michael@0: template michael@0: void TestTilde(const T& t) michael@0: { michael@0: typedef typename mozilla::detail::UnsignedIntegerTypeForEnum::Type michael@0: UnsignedIntegerType; michael@0: michael@0: auto result = ~t; michael@0: michael@0: typedef decltype(result) ResultType; michael@0: michael@0: RequireLiteralType(); michael@0: TestNonConvertibilityForOneType(); michael@0: michael@0: UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(t)); michael@0: michael@0: MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result)); michael@0: MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result)); michael@0: MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result)); michael@0: MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result)); michael@0: MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result)); michael@0: } michael@0: michael@0: // Helper dispatching a given triple of operands to all operator-specific michael@0: // testing functions. michael@0: template michael@0: void TestAllOpsForGivenOperands(const T1& t1, const T2& t2, const T3& t3) michael@0: { michael@0: TestBinOp(t1, t2, t3); michael@0: TestBinOp(t1, t2, t3); michael@0: TestBinOp(t1, t2, t3); michael@0: TestTilde(t1); michael@0: } michael@0: michael@0: // Helper building various triples of operands using a given operator, michael@0: // and testing all operators with them. michael@0: template michael@0: void TestAllOpsForOperandsBuiltUsingGivenOp() michael@0: { michael@0: // The type of enum values like TypedEnum::A may be different from michael@0: // TypedEnum. That is the case in the legacy non-C++11 path. We want to michael@0: // ensure good test coverage even when these two types are distinct. michael@0: // To that effect, we have both 'auto' typed variables, preserving the michael@0: // original type of enum values, and 'plain' typed variables, that michael@0: // are plain TypedEnum's. michael@0: michael@0: const TypedEnum a_plain = TypedEnum::A; michael@0: const TypedEnum b_plain = TypedEnum::B; michael@0: const TypedEnum c_plain = TypedEnum::C; michael@0: michael@0: auto a_auto = TypedEnum::A; michael@0: auto b_auto = TypedEnum::B; michael@0: auto c_auto = TypedEnum::C; michael@0: michael@0: auto ab_plain = Op(a_plain, b_plain); michael@0: auto bc_plain = Op(b_plain, c_plain); michael@0: auto ab_auto = Op(a_auto, b_auto); michael@0: auto bc_auto = Op(b_auto, c_auto); michael@0: michael@0: // On each row below, we pass a triple of operands. Keep in mind that this michael@0: // is going to be received as (t1, t2, t3) and the actual tests performed michael@0: // will be of the form michael@0: // michael@0: // result = t1 Op t2; michael@0: // result Op= t3; michael@0: // michael@0: // For this reason, we carefully ensure that the values of (t1, t2) michael@0: // systematically cover all types of such pairs; to limit complexity, michael@0: // we are not so careful with t3, and we just try to pass t3's michael@0: // that may lead to nontrivial bitwise operations. michael@0: TestAllOpsForGivenOperands(a_plain, b_plain, c_plain); michael@0: TestAllOpsForGivenOperands(a_plain, bc_plain, b_auto); michael@0: TestAllOpsForGivenOperands(ab_plain, c_plain, a_plain); michael@0: TestAllOpsForGivenOperands(ab_plain, bc_plain, a_auto); michael@0: michael@0: TestAllOpsForGivenOperands(a_plain, b_auto, c_plain); michael@0: TestAllOpsForGivenOperands(a_plain, bc_auto, b_auto); michael@0: TestAllOpsForGivenOperands(ab_plain, c_auto, a_plain); michael@0: TestAllOpsForGivenOperands(ab_plain, bc_auto, a_auto); michael@0: michael@0: TestAllOpsForGivenOperands(a_auto, b_plain, c_plain); michael@0: TestAllOpsForGivenOperands(a_auto, bc_plain, b_auto); michael@0: TestAllOpsForGivenOperands(ab_auto, c_plain, a_plain); michael@0: TestAllOpsForGivenOperands(ab_auto, bc_plain, a_auto); michael@0: michael@0: TestAllOpsForGivenOperands(a_auto, b_auto, c_plain); michael@0: TestAllOpsForGivenOperands(a_auto, bc_auto, b_auto); michael@0: TestAllOpsForGivenOperands(ab_auto, c_auto, a_plain); michael@0: TestAllOpsForGivenOperands(ab_auto, bc_auto, a_auto); michael@0: } michael@0: michael@0: // Tests all bitwise operations on a given TypedEnum bitfield. michael@0: template michael@0: void michael@0: TestTypedEnumBitField() michael@0: { michael@0: TestTypedEnumBasics(); michael@0: michael@0: TestAllOpsForOperandsBuiltUsingGivenOp(); michael@0: TestAllOpsForOperandsBuiltUsingGivenOp(); michael@0: TestAllOpsForOperandsBuiltUsingGivenOp(); michael@0: } michael@0: michael@0: // Checks that enum bitwise expressions have the same non-convertibility properties as michael@0: // c++11 enum classes do, i.e. not implicitly convertible to anything michael@0: // (though *explicitly* convertible). michael@0: void TestNoConversionsBetweenUnrelatedTypes() michael@0: { michael@0: using mozilla::IsConvertible; michael@0: michael@0: // Two typed enum classes having the same underlying integer type, to ensure that michael@0: // we would catch bugs accidentally allowing conversions in that case. michael@0: typedef CharEnumBitField T1; michael@0: typedef Nested::CharEnumBitField T2; michael@0: michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: michael@0: // The following are #ifdef MOZ_HAVE_EXPLICIT_CONVERSION because michael@0: // without support for explicit conversion operators, we can't easily have these michael@0: // bad conversions completely removed. They still do fail to compile in practice, michael@0: // but not in a way that we can static_assert on. michael@0: #ifdef MOZ_HAVE_EXPLICIT_CONVERSION michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: static_assert(!IsConvertible::value, michael@0: "should not be convertible"); michael@0: #endif michael@0: } michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Int8EnumWithHighBits, int8_t) michael@0: A = 0x20, michael@0: B = 0x40 michael@0: MOZ_END_ENUM_CLASS(Int8EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Uint8EnumWithHighBits, uint8_t) michael@0: A = 0x40, michael@0: B = 0x80 michael@0: MOZ_END_ENUM_CLASS(Uint8EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Int16EnumWithHighBits, int16_t) michael@0: A = 0x2000, michael@0: B = 0x4000 michael@0: MOZ_END_ENUM_CLASS(Int16EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Uint16EnumWithHighBits, uint16_t) michael@0: A = 0x4000, michael@0: B = 0x8000 michael@0: MOZ_END_ENUM_CLASS(Uint16EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Int32EnumWithHighBits, int32_t) michael@0: A = 0x20000000, michael@0: B = 0x40000000 michael@0: MOZ_END_ENUM_CLASS(Int32EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Uint32EnumWithHighBits, uint32_t) michael@0: A = 0x40000000u, michael@0: B = 0x80000000u michael@0: MOZ_END_ENUM_CLASS(Uint32EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Int64EnumWithHighBits, int64_t) michael@0: A = 0x2000000000000000ll, michael@0: B = 0x4000000000000000ll michael@0: MOZ_END_ENUM_CLASS(Int64EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits) michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(Uint64EnumWithHighBits, uint64_t) michael@0: A = 0x4000000000000000ull, michael@0: B = 0x8000000000000000ull michael@0: MOZ_END_ENUM_CLASS(Uint64EnumWithHighBits) michael@0: MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits) michael@0: michael@0: // Checks that we don't accidentally truncate high bits by coercing to the wrong michael@0: // integer type internally when implementing bitwise ops. michael@0: template michael@0: void TestIsNotTruncated() michael@0: { michael@0: EnumType a = EnumType::A; michael@0: EnumType b = EnumType::B; michael@0: MOZ_RELEASE_ASSERT(IntType(a)); michael@0: MOZ_RELEASE_ASSERT(IntType(b)); michael@0: MOZ_RELEASE_ASSERT(a | EnumType::B); michael@0: MOZ_RELEASE_ASSERT(a | b); michael@0: MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B); michael@0: EnumType c = EnumType::A | EnumType::B; michael@0: MOZ_RELEASE_ASSERT(IntType(c)); michael@0: MOZ_RELEASE_ASSERT(c & c); michael@0: MOZ_RELEASE_ASSERT(c | c); michael@0: MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B)); michael@0: MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B)); michael@0: MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B)); michael@0: MOZ_RELEASE_ASSERT(c & EnumType::A); michael@0: MOZ_RELEASE_ASSERT(c & EnumType::B); michael@0: EnumType d = EnumType::A; michael@0: d |= EnumType::B; michael@0: MOZ_RELEASE_ASSERT(d == c); michael@0: } michael@0: michael@0: int michael@0: main() michael@0: { michael@0: TestTypedEnumBasics(); michael@0: TestTypedEnumBasics(); michael@0: TestTypedEnumBasics(); michael@0: TestTypedEnumBasics(); michael@0: michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: TestTypedEnumBitField(); michael@0: michael@0: TestNoConversionsBetweenUnrelatedTypes(); michael@0: michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: TestIsNotTruncated(); michael@0: michael@0: return 0; michael@0: }