зеркало из https://github.com/mozilla/gecko-dev.git
504 строки
18 KiB
C++
504 строки
18 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/TypedEnumBits.h"
|
|
|
|
#include <stdint.h>
|
|
#include <type_traits>
|
|
|
|
// A rough feature check for is_literal_type. Not very carefully checked.
|
|
// Feel free to amend as needed.
|
|
// We leave ANDROID out because it's using stlport which doesn't have
|
|
// std::is_literal_type.
|
|
#if __cplusplus >= 201103L && !defined(ANDROID)
|
|
# if defined(__clang__)
|
|
/*
|
|
* Per Clang documentation, "Note that marketing version numbers should not
|
|
* be used to check for language features, as different vendors use different
|
|
* numbering schemes. Instead, use the feature checking macros."
|
|
*/
|
|
# ifndef __has_extension
|
|
# define __has_extension \
|
|
__has_feature /* compatibility, for older versions of clang */
|
|
# endif
|
|
# if __has_extension(is_literal) && __has_include(<type_traits>)
|
|
# define MOZ_HAVE_IS_LITERAL
|
|
# endif
|
|
# elif defined(__GNUC__) || defined(_MSC_VER)
|
|
# define MOZ_HAVE_IS_LITERAL
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(MOZ_HAVE_IS_LITERAL) && defined(MOZ_HAVE_CXX11_CONSTEXPR)
|
|
# include <type_traits>
|
|
template <typename T>
|
|
void RequireLiteralType() {
|
|
static_assert(std::is_literal_type<T>::value, "Expected a literal type");
|
|
}
|
|
#else // not MOZ_HAVE_IS_LITERAL
|
|
template <typename T>
|
|
void RequireLiteralType() {}
|
|
#endif
|
|
|
|
template <typename T>
|
|
void RequireLiteralType(const T&) {
|
|
RequireLiteralType<T>();
|
|
}
|
|
|
|
enum class AutoEnum { A, B = -3, C };
|
|
|
|
enum class CharEnum : char { A, B = 3, C };
|
|
|
|
enum class AutoEnumBitField { A = 0x10, B = 0x20, C };
|
|
|
|
enum class CharEnumBitField : char { A = 0x10, B, C = 0x40 };
|
|
|
|
struct Nested {
|
|
enum class AutoEnum { A, B, C = -1 };
|
|
|
|
enum class CharEnum : char { A = 4, B, C = 1 };
|
|
|
|
enum class AutoEnumBitField { A, B = 0x20, C };
|
|
|
|
enum class CharEnumBitField : char { A = 1, B = 1, C = 1 };
|
|
};
|
|
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField)
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField)
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField)
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField)
|
|
|
|
#define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \
|
|
enum class BitFieldFor_##IntType : IntType{ \
|
|
A = 1, \
|
|
B = 2, \
|
|
C = 4, \
|
|
}; \
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType)
|
|
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(char)
|
|
typedef signed char signed_char;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char)
|
|
typedef unsigned char unsigned_char;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(short)
|
|
typedef unsigned short unsigned_short;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(int)
|
|
typedef unsigned int unsigned_int;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int)
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(long)
|
|
typedef unsigned long unsigned_long;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long)
|
|
typedef long long long_long;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long)
|
|
typedef unsigned long long unsigned_long_long;
|
|
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long)
|
|
|
|
#undef MAKE_STANDARD_BITFIELD_FOR_TYPE
|
|
|
|
template <typename T>
|
|
void TestNonConvertibilityForOneType() {
|
|
static_assert(!std::is_convertible_v<T, bool>, "should not be convertible");
|
|
static_assert(!std::is_convertible_v<T, int>, "should not be convertible");
|
|
static_assert(!std::is_convertible_v<T, uint64_t>,
|
|
"should not be convertible");
|
|
|
|
static_assert(!std::is_convertible_v<bool, T>, "should not be convertible");
|
|
static_assert(!std::is_convertible_v<int, T>, "should not be convertible");
|
|
static_assert(!std::is_convertible_v<uint64_t, T>,
|
|
"should not be convertible");
|
|
}
|
|
|
|
template <typename TypedEnum>
|
|
void TestTypedEnumBasics() {
|
|
const TypedEnum a = TypedEnum::A;
|
|
int unused = int(a);
|
|
(void)unused;
|
|
RequireLiteralType(TypedEnum::A);
|
|
RequireLiteralType(a);
|
|
TestNonConvertibilityForOneType<TypedEnum>();
|
|
}
|
|
|
|
// Op wraps a bitwise binary operator, passed as a char template parameter,
|
|
// and applies it to its arguments (aT1, aT2). For example,
|
|
//
|
|
// Op<'|'>(aT1, aT2)
|
|
//
|
|
// is the same as
|
|
//
|
|
// aT1 | aT2.
|
|
//
|
|
template <char o, typename T1, typename T2>
|
|
auto Op(const T1& aT1, const T2& aT2)
|
|
-> decltype(aT1 | aT2) // See the static_assert's below --- the return type
|
|
// depends solely on the operands type, not on the
|
|
// choice of operation.
|
|
{
|
|
static_assert(std::is_same_v<decltype(aT1 | aT2), decltype(aT1 & aT2)>,
|
|
"binary ops should have the same result type");
|
|
static_assert(std::is_same_v<decltype(aT1 | aT2), decltype(aT1 ^ aT2)>,
|
|
"binary ops should have the same result type");
|
|
|
|
static_assert(o == '|' || o == '&' || o == '^',
|
|
"unexpected operator character");
|
|
|
|
return o == '|' ? aT1 | aT2 : o == '&' ? aT1 & aT2 : aT1 ^ aT2;
|
|
}
|
|
|
|
// OpAssign wraps a bitwise binary operator, passed as a char template
|
|
// parameter, and applies the corresponding compound-assignment operator to its
|
|
// arguments (aT1, aT2). For example,
|
|
//
|
|
// OpAssign<'|'>(aT1, aT2)
|
|
//
|
|
// is the same as
|
|
//
|
|
// aT1 |= aT2.
|
|
//
|
|
template <char o, typename T1, typename T2>
|
|
T1& OpAssign(T1& aT1, const T2& aT2) {
|
|
static_assert(o == '|' || o == '&' || o == '^',
|
|
"unexpected operator character");
|
|
|
|
switch (o) {
|
|
case '|':
|
|
return aT1 |= aT2;
|
|
case '&':
|
|
return aT1 &= aT2;
|
|
case '^':
|
|
return aT1 ^= aT2;
|
|
default:
|
|
MOZ_CRASH();
|
|
}
|
|
}
|
|
|
|
// Tests a single binary bitwise operator, using a single set of three operands.
|
|
// The operations tested are:
|
|
//
|
|
// result = aT1 Op aT2;
|
|
// result Op= aT3;
|
|
//
|
|
// Where Op is the operator specified by the char template parameter 'o' and
|
|
// can be any of '|', '&', '^'.
|
|
//
|
|
// Note that the operands aT1, aT2, aT3 are intentionally passed with free
|
|
// types (separate template parameters for each) because their type may
|
|
// actually be different from TypedEnum:
|
|
//
|
|
// 1) Their type could be CastableTypedEnumResult<TypedEnum> if they are
|
|
// the result of a bitwise operation themselves;
|
|
// 2) In the non-c++11 legacy path, the type of enum values is also
|
|
// different from TypedEnum.
|
|
//
|
|
template <typename TypedEnum, char o, typename T1, typename T2, typename T3>
|
|
void TestBinOp(const T1& aT1, const T2& aT2, const T3& aT3) {
|
|
typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
|
|
UnsignedIntegerType;
|
|
|
|
// Part 1:
|
|
// Test the bitwise binary operator i.e.
|
|
// result = aT1 Op aT2;
|
|
auto result = Op<o>(aT1, aT2);
|
|
|
|
typedef decltype(result) ResultType;
|
|
|
|
RequireLiteralType<ResultType>();
|
|
TestNonConvertibilityForOneType<ResultType>();
|
|
|
|
UnsignedIntegerType unsignedIntegerResult =
|
|
Op<o>(UnsignedIntegerType(aT1), UnsignedIntegerType(aT2));
|
|
|
|
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
|
|
MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
|
|
MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
|
|
MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
|
|
MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
|
|
|
|
// Part 2:
|
|
// Test the compound-assignment operator, i.e.
|
|
// result Op= aT3;
|
|
TypedEnum newResult = result;
|
|
OpAssign<o>(newResult, aT3);
|
|
UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult;
|
|
OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(aT3));
|
|
MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult);
|
|
|
|
// Part 3:
|
|
// Test additional boolean operators that we unfortunately had to add to
|
|
// CastableTypedEnumResult at some point to please some compiler,
|
|
// even though bool convertibility should have been enough.
|
|
MOZ_RELEASE_ASSERT(result == TypedEnum(result));
|
|
MOZ_RELEASE_ASSERT(!(result != TypedEnum(result)));
|
|
MOZ_RELEASE_ASSERT((result && true) == bool(result));
|
|
MOZ_RELEASE_ASSERT((result && false) == false);
|
|
MOZ_RELEASE_ASSERT((true && result) == bool(result));
|
|
MOZ_RELEASE_ASSERT((false && result && false) == false);
|
|
MOZ_RELEASE_ASSERT((result || false) == bool(result));
|
|
MOZ_RELEASE_ASSERT((result || true) == true);
|
|
MOZ_RELEASE_ASSERT((false || result) == bool(result));
|
|
MOZ_RELEASE_ASSERT((true || result) == true);
|
|
|
|
// Part 4:
|
|
// Test short-circuit evaluation.
|
|
auto Explode = [] {
|
|
// This function should never be called. Return an arbitrary value.
|
|
MOZ_RELEASE_ASSERT(false);
|
|
return false;
|
|
};
|
|
if (result) {
|
|
MOZ_RELEASE_ASSERT(result || Explode());
|
|
MOZ_RELEASE_ASSERT(!(!result && Explode()));
|
|
} else {
|
|
MOZ_RELEASE_ASSERT(!(result && Explode()));
|
|
MOZ_RELEASE_ASSERT(!result || Explode());
|
|
}
|
|
}
|
|
|
|
// Similar to TestBinOp but testing the unary ~ operator.
|
|
template <typename TypedEnum, typename T>
|
|
void TestTilde(const T& aT) {
|
|
typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
|
|
UnsignedIntegerType;
|
|
|
|
auto result = ~aT;
|
|
|
|
typedef decltype(result) ResultType;
|
|
|
|
RequireLiteralType<ResultType>();
|
|
TestNonConvertibilityForOneType<ResultType>();
|
|
|
|
UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(aT));
|
|
|
|
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
|
|
MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
|
|
MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
|
|
MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
|
|
MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
|
|
}
|
|
|
|
// Helper dispatching a given triple of operands to all operator-specific
|
|
// testing functions.
|
|
template <typename TypedEnum, typename T1, typename T2, typename T3>
|
|
void TestAllOpsForGivenOperands(const T1& aT1, const T2& aT2, const T3& aT3) {
|
|
TestBinOp<TypedEnum, '|'>(aT1, aT2, aT3);
|
|
TestBinOp<TypedEnum, '&'>(aT1, aT2, aT3);
|
|
TestBinOp<TypedEnum, '^'>(aT1, aT2, aT3);
|
|
TestTilde<TypedEnum>(aT1);
|
|
}
|
|
|
|
// Helper building various triples of operands using a given operator,
|
|
// and testing all operators with them.
|
|
template <typename TypedEnum, char o>
|
|
void TestAllOpsForOperandsBuiltUsingGivenOp() {
|
|
// The type of enum values like TypedEnum::A may be different from
|
|
// TypedEnum. That is the case in the legacy non-C++11 path. We want to
|
|
// ensure good test coverage even when these two types are distinct.
|
|
// To that effect, we have both 'auto' typed variables, preserving the
|
|
// original type of enum values, and 'plain' typed variables, that
|
|
// are plain TypedEnum's.
|
|
|
|
const TypedEnum a_plain = TypedEnum::A;
|
|
const TypedEnum b_plain = TypedEnum::B;
|
|
const TypedEnum c_plain = TypedEnum::C;
|
|
|
|
auto a_auto = TypedEnum::A;
|
|
auto b_auto = TypedEnum::B;
|
|
auto c_auto = TypedEnum::C;
|
|
|
|
auto ab_plain = Op<o>(a_plain, b_plain);
|
|
auto bc_plain = Op<o>(b_plain, c_plain);
|
|
auto ab_auto = Op<o>(a_auto, b_auto);
|
|
auto bc_auto = Op<o>(b_auto, c_auto);
|
|
|
|
// On each row below, we pass a triple of operands. Keep in mind that this
|
|
// is going to be received as (aT1, aT2, aT3) and the actual tests performed
|
|
// will be of the form
|
|
//
|
|
// result = aT1 Op aT2;
|
|
// result Op= aT3;
|
|
//
|
|
// For this reason, we carefully ensure that the values of (aT1, aT2)
|
|
// systematically cover all types of such pairs; to limit complexity,
|
|
// we are not so careful with aT3, and we just try to pass aT3's
|
|
// that may lead to nontrivial bitwise operations.
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_plain, c_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_plain, b_auto);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain, a_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto);
|
|
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_auto, c_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_auto, b_auto);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto, a_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto, a_auto);
|
|
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_plain, c_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_plain, b_auto);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_plain, a_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_plain, a_auto);
|
|
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_auto, c_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_auto, b_auto);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_auto, a_plain);
|
|
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_auto, a_auto);
|
|
}
|
|
|
|
// Tests all bitwise operations on a given TypedEnum bitfield.
|
|
template <typename TypedEnum>
|
|
void TestTypedEnumBitField() {
|
|
TestTypedEnumBasics<TypedEnum>();
|
|
|
|
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>();
|
|
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>();
|
|
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>();
|
|
}
|
|
|
|
// Checks that enum bitwise expressions have the same non-convertibility
|
|
// properties as c++11 enum classes do, i.e. not implicitly convertible to
|
|
// anything (though *explicitly* convertible).
|
|
void TestNoConversionsBetweenUnrelatedTypes() {
|
|
// Two typed enum classes having the same underlying integer type, to ensure
|
|
// that we would catch bugs accidentally allowing conversions in that case.
|
|
typedef CharEnumBitField T1;
|
|
typedef Nested::CharEnumBitField T2;
|
|
|
|
static_assert(!std::is_convertible_v<T1, T2>, "should not be convertible");
|
|
static_assert(!std::is_convertible_v<T1, decltype(T2::A)>,
|
|
"should not be convertible");
|
|
static_assert(!std::is_convertible_v<T1, decltype(T2::A | T2::B)>,
|
|
"should not be convertible");
|
|
|
|
static_assert(!std::is_convertible_v<decltype(T1::A), T2>,
|
|
"should not be convertible");
|
|
static_assert(!std::is_convertible_v<decltype(T1::A), decltype(T2::A)>,
|
|
"should not be convertible");
|
|
static_assert(
|
|
!std::is_convertible_v<decltype(T1::A), decltype(T2::A | T2::B)>,
|
|
"should not be convertible");
|
|
|
|
static_assert(!std::is_convertible_v<decltype(T1::A | T1::B), T2>,
|
|
"should not be convertible");
|
|
static_assert(
|
|
!std::is_convertible_v<decltype(T1::A | T1::B), decltype(T2::A)>,
|
|
"should not be convertible");
|
|
static_assert(
|
|
!std::is_convertible_v<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>,
|
|
"should not be convertible");
|
|
}
|
|
|
|
enum class Int8EnumWithHighBits : int8_t { A = 0x20, B = 0x40 };
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits)
|
|
|
|
enum class Uint8EnumWithHighBits : uint8_t { A = 0x40, B = 0x80 };
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits)
|
|
|
|
enum class Int16EnumWithHighBits : int16_t { A = 0x2000, B = 0x4000 };
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits)
|
|
|
|
enum class Uint16EnumWithHighBits : uint16_t { A = 0x4000, B = 0x8000 };
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits)
|
|
|
|
enum class Int32EnumWithHighBits : int32_t { A = 0x20000000, B = 0x40000000 };
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits)
|
|
|
|
enum class Uint32EnumWithHighBits : uint32_t {
|
|
A = 0x40000000u,
|
|
B = 0x80000000u
|
|
};
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits)
|
|
|
|
enum class Int64EnumWithHighBits : int64_t {
|
|
A = 0x2000000000000000ll,
|
|
B = 0x4000000000000000ll
|
|
};
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits)
|
|
|
|
enum class Uint64EnumWithHighBits : uint64_t {
|
|
A = 0x4000000000000000ull,
|
|
B = 0x8000000000000000ull
|
|
};
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits)
|
|
|
|
// Checks that we don't accidentally truncate high bits by coercing to the wrong
|
|
// integer type internally when implementing bitwise ops.
|
|
template <typename EnumType, typename IntType>
|
|
void TestIsNotTruncated() {
|
|
EnumType a = EnumType::A;
|
|
EnumType b = EnumType::B;
|
|
MOZ_RELEASE_ASSERT(IntType(a));
|
|
MOZ_RELEASE_ASSERT(IntType(b));
|
|
MOZ_RELEASE_ASSERT(a | EnumType::B);
|
|
MOZ_RELEASE_ASSERT(a | b);
|
|
MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B);
|
|
EnumType c = EnumType::A | EnumType::B;
|
|
MOZ_RELEASE_ASSERT(IntType(c));
|
|
MOZ_RELEASE_ASSERT(c & c);
|
|
MOZ_RELEASE_ASSERT(c | c);
|
|
MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B));
|
|
MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B));
|
|
MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B));
|
|
MOZ_RELEASE_ASSERT(c & EnumType::A);
|
|
MOZ_RELEASE_ASSERT(c & EnumType::B);
|
|
EnumType d = EnumType::A;
|
|
d |= EnumType::B;
|
|
MOZ_RELEASE_ASSERT(d == c);
|
|
}
|
|
|
|
int main() {
|
|
TestTypedEnumBasics<AutoEnum>();
|
|
TestTypedEnumBasics<CharEnum>();
|
|
TestTypedEnumBasics<Nested::AutoEnum>();
|
|
TestTypedEnumBasics<Nested::CharEnum>();
|
|
|
|
TestTypedEnumBitField<AutoEnumBitField>();
|
|
TestTypedEnumBitField<CharEnumBitField>();
|
|
TestTypedEnumBitField<Nested::AutoEnumBitField>();
|
|
TestTypedEnumBitField<Nested::CharEnumBitField>();
|
|
|
|
TestTypedEnumBitField<BitFieldFor_uint8_t>();
|
|
TestTypedEnumBitField<BitFieldFor_int8_t>();
|
|
TestTypedEnumBitField<BitFieldFor_uint16_t>();
|
|
TestTypedEnumBitField<BitFieldFor_int16_t>();
|
|
TestTypedEnumBitField<BitFieldFor_uint32_t>();
|
|
TestTypedEnumBitField<BitFieldFor_int32_t>();
|
|
TestTypedEnumBitField<BitFieldFor_uint64_t>();
|
|
TestTypedEnumBitField<BitFieldFor_int64_t>();
|
|
TestTypedEnumBitField<BitFieldFor_char>();
|
|
TestTypedEnumBitField<BitFieldFor_signed_char>();
|
|
TestTypedEnumBitField<BitFieldFor_unsigned_char>();
|
|
TestTypedEnumBitField<BitFieldFor_short>();
|
|
TestTypedEnumBitField<BitFieldFor_unsigned_short>();
|
|
TestTypedEnumBitField<BitFieldFor_int>();
|
|
TestTypedEnumBitField<BitFieldFor_unsigned_int>();
|
|
TestTypedEnumBitField<BitFieldFor_long>();
|
|
TestTypedEnumBitField<BitFieldFor_unsigned_long>();
|
|
TestTypedEnumBitField<BitFieldFor_long_long>();
|
|
TestTypedEnumBitField<BitFieldFor_unsigned_long_long>();
|
|
|
|
TestNoConversionsBetweenUnrelatedTypes();
|
|
|
|
TestIsNotTruncated<Int8EnumWithHighBits, int8_t>();
|
|
TestIsNotTruncated<Int16EnumWithHighBits, int16_t>();
|
|
TestIsNotTruncated<Int32EnumWithHighBits, int32_t>();
|
|
TestIsNotTruncated<Int64EnumWithHighBits, int64_t>();
|
|
TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>();
|
|
TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>();
|
|
TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>();
|
|
TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>();
|
|
|
|
return 0;
|
|
}
|