Skip to content
Commit 38b7a97e authored by Pedro Alves's avatar Pedro Alves
Browse files

enum_flags: Fix problems and add comprehensive unit tests

This patch starts by adding comprehensive unit tests for enum_flags.

It adds:

 - tests of normal expected uses of the API.

 - checks that _invalid_ uses of the API would fail to compile.  I.e.,
   it validates that enum_flags really is a strong type, and that
   incorrect mixing of enum types would be caught at compile time.  It
   pulls that off making use of SFINEA and C++11's decltype/constexpr.

This revealed many holes in the enum_flags API.  For example, the f1
assignment below currently incorrectly fails to compile:

 enum_flags<flags> f1 = FLAG1;
 enum_flags<flags> f2 = FLAG2 | f1;

This hole and more are all plugged by this patch, by reworking how the
enum_flags operators are implemented, and making use of C++11's
feature of being able to delete methods/functions.

This makes most of the enum_flags operators constexpr.  Beyond
enabling more compiler optimizations and enabling the new unit tests,
this has other advantages, like making it possible to use operator|
with enum_flags values in switch cases, where only compile-time
constants are allowed:

    enum_flags<flags> f = FLAG1 | FLAG2;
    switch (f)
      {
      case FLAG1 | FLAG2:
	break;
      }

Currently that fails to compile.

This adds a STATIC_SELF_TEST macro to selftest.h, which is a variant
of SELF_TEST, but uses C++11's static_assert to do checking at compile
time.

To avoid potential ODR violations, since the tests add enums with
short names that could easily conflict with other names, the new
selftests are placed in a namespace (selftests::enum_flags_tests).  I
think that's a good practice that we should start following.  This
required splitting the global operator overload enablement out of the
DEF_ENUM_FLAGS_TYPE macro into a separate macro, because
DEF_ENUM_FLAGS_TYPE wants to create the enum flags typedef in the
global namespace too.

Tested with gcc 4.8, 4.9, 5.3, 7 (trunk) and clang 3.7.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* Makefile.in (COMMON_OBS): Add enum-flags-selftests.o.
	* common/enum-flags.h (ENABLE_ENUM_FLAGS_OPERATORS): New, factored
	out from DEF_ENUM_FLAGS_TYPE.
	(enum_flags::underlying_value): Delete.
	(enum_flags::enum_flags): Use default.
	(enum_flags::operator=): Delete.
	(enum_flags::enum_flags(enum_type e)): Now constexpr.
	(enum_flags::enum_flags(enum_flags::zero_type *zero)): Likewise.
	(enum_flags::operator&=(enum_type e)): No longer implement in
	terms of the underlying type here.
	(enum_flags::operator|=(enum_type e)): Likewise.
	(enum_flags::operator^=(enum_type e)): Likewise.
	(enum_flags::enum_type ()): Now constexpr.
	(enum_flags::enum_flags operator&(enum_type e)): Delete.
	(enum_flags::operator|(enum_type e)): Delete.
	(enum_flags::operator^(enum_type e)): Delete.
	(enum_flags::operator~()): Now constexpr.
	(operator&, operator|, operator^): Delete.
	(ENUM_FLAGS_GEN_BINOP, ENUM_FLAGS_GEN_COMPOUND_ASSIGN): New,
	reimplementing global operators.
	(operator~): Now constexpr and reimplemented.
	(operator<<, operator>>): New deleted functions.
	* enum-flags-selftests.c: New file.
	* go-exp.y (parse_string_or_char): Add cast to int.
	* selftest.h (SC_STRINGIZE_1, SC_STRINGIZE)
	(STATIC_SELF_CHECK_FAIL_MSG, STATIC_SELF_CHECK): New.
parent de2bb891
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment