From 1682814b3ef44298c7e2e8bba3974952ca4c9597 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 4 Oct 2013 13:17:13 -0400 Subject: [PATCH] Bug 918436 - Make the type argument of MOZ_BEGIN(_NESTED)_ENUM_CLASS optional and add tests. r=Waldo --- mfbt/TypedEnum.h | 60 ++++++++++++++++++++++++++++++------ mfbt/tests/TestTypedEnum.cpp | 40 ++++++++++++++++++++++++ mfbt/tests/moz.build | 1 + 3 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 mfbt/tests/TestTypedEnum.cpp diff --git a/mfbt/TypedEnum.h b/mfbt/TypedEnum.h index 6f595cb4c5f..180f98eaa24 100644 --- a/mfbt/TypedEnum.h +++ b/mfbt/TypedEnum.h @@ -72,7 +72,7 @@ * strongly-typed enumeration feature of C++11 ("enum class"). If supported * by the compiler, an enum defined using these macros will not be implicitly * converted to any other type, and its enumerators will be scoped using the - * enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName, type) in place of + * enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing * "};". For example, * @@ -87,10 +87,9 @@ * fail. In other compilers, Enum itself will actually be defined as a class, * and some implicit conversions will fail while others will succeed. * - * The type argument specifies the underlying type for the enum where - * supported, as with MOZ_ENUM_TYPE(). For simplicity, it is currently - * mandatory. As with MOZ_ENUM_TYPE(), it will do nothing on compilers that do - * not support it. + * The optional type argument specifies the underlying type for the enum where + * supported, as with MOZ_ENUM_TYPE(). As with MOZ_ENUM_TYPE(), it will do + * nothing on compilers that do not support it. * * MOZ_{BEGIN,END}_ENUM_CLASS doesn't work for defining enum classes nested * inside classes. To define an enum class nested inside another class, use @@ -114,7 +113,12 @@ * All compilers that support strong enums also support an explicit * underlying type, so no extra check is needed. */ -# define MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type) \ + + /* Single-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \ + enum class Name { + /* Two-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \ enum class Name : type { # define MOZ_END_NESTED_ENUM_CLASS(Name) \ }; @@ -154,8 +158,17 @@ * { * return Enum::A; * } - */\ -# define MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type) \ + */ + + /* Single-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \ + class Name \ + { \ + public: \ + enum Enum \ + { + /* Two-argument form. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \ class Name \ { \ public: \ @@ -226,7 +239,36 @@ inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \ inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE; #endif -# define MOZ_BEGIN_ENUM_CLASS(Name, type) MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type) + + /* + * Count the number of arguments passed to MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS, + * very carefully tiptoeing around an MSVC bug where it improperly expands + * __VA_ARGS__ as a single token in argument lists. See these URLs for + * details: + * + * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement + * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 + */ +# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL2(_1, _2, count, ...) \ + count +# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL(args) \ + MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL2 args +# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS(...) \ + MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL((__VA_ARGS__, 2, 1, 0)) + /* Pick the right helper macro to invoke. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER2(count) \ + MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER##count +# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER1(count) \ + MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER2(count) +# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER(count) \ + MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER1(count) + /* The actual macro. */ +# define MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(x, y) x y +# define MOZ_BEGIN_NESTED_ENUM_CLASS(...) \ + MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER(MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS(__VA_ARGS__)), \ + (__VA_ARGS__)) + +# define MOZ_BEGIN_ENUM_CLASS(...) MOZ_BEGIN_NESTED_ENUM_CLASS(__VA_ARGS__) # define MOZ_END_ENUM_CLASS(Name) \ MOZ_END_NESTED_ENUM_CLASS(Name) \ MOZ_FINISH_NESTED_ENUM_CLASS(Name) diff --git a/mfbt/tests/TestTypedEnum.cpp b/mfbt/tests/TestTypedEnum.cpp new file mode 100644 index 00000000000..0e76ad24b5f --- /dev/null +++ b/mfbt/tests/TestTypedEnum.cpp @@ -0,0 +1,40 @@ +/* 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/TypedEnum.h" + +MOZ_BEGIN_ENUM_CLASS(AutoEnum) + A, + B +MOZ_END_ENUM_CLASS(AutoEnum) + + +MOZ_BEGIN_ENUM_CLASS(CharEnum, char) + A, + B +MOZ_END_ENUM_CLASS(CharEnum) + +struct Nested +{ + MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnum) + C + MOZ_END_NESTED_ENUM_CLASS(AutoEnum) + + MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnum, char) + D = 4, + E + MOZ_END_NESTED_ENUM_CLASS(CharEnum) +}; + +// Simply check that this compiles. +const AutoEnum autoEnum = AutoEnum::A; +const CharEnum charEnum = CharEnum::B; +const Nested::AutoEnum nestedAutoEnum = Nested::AutoEnum::C; +const Nested::CharEnum nestedCharEnum = Nested::CharEnum::D; + +int +main() +{ +} diff --git a/mfbt/tests/moz.build b/mfbt/tests/moz.build index 1da3210d0c9..cd18fdf8923 100644 --- a/mfbt/tests/moz.build +++ b/mfbt/tests/moz.build @@ -17,6 +17,7 @@ CPP_UNIT_TESTS += [ 'TestIntegerPrintfMacros.cpp', 'TestSHA1.cpp', 'TestTypeTraits.cpp', + 'TestTypedEnum.cpp', 'TestWeakPtr.cpp', ]