summaryrefslogtreecommitdiff
path: root/gdb/enum-flags-selftests.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-11-04 02:02:39 +0000
committerPedro Alves <palves@redhat.com>2016-11-04 03:38:44 +0000
commit1d71bdc242616819a8d4ace8d7a703fdbd90e602 (patch)
treea00acb1f49d09ebdd1f2939d7173cfa947b6ce27 /gdb/enum-flags-selftests.c
parent6f0f2be472d6e7dd37bf82841002674fa759b1b2 (diff)
downloadbinutils-gdb-palves/cxx-enum-flags.tar.gz
enum_flags: Fix ternary operator and remove implicit convertion to raw enumpalves/cxx-enum-flags
The unit tests added by the previous patch revealed that this useful use case doesn't work: enum flag { FLAG1 = 1, FLAG2 = 2 }; enum_flags<flag> src = FLAG1; enum_flags<flag> f1 = condition ? src : FLAG2; It fails to compile because enum_flags<flag> and flag are convertible to each other. Turns out that making enum_flags be implicitly convertible to the backing raw enum type was not a good idea. If we make it convertible to the underlying type instead, we fix that ternary operator use case, and, we find cases throughout the codebase that should be using the enum_flags but were using the raw backing enum instead. So it's a good change overall. There's one case in compile/compile-c-types.c where we need to call a function in a C API that expects the raw enum. To address cases like that, this adds a "raw()" method to enum_flags. This way we can keep using the safer enum_flags to construct the value, and then be explicit when we need to get at the raw enum. 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> * common/enum-flags.h (enum_flags::operator&=): Change parameter type to enum_flags from enum_type and adjust. (enum_flags::operator|=): Likewise. (enum_flags::operator^=): Likewise. (enum_flags::operator enum_type): Delete. (enum_flags::raw): New method. (ENUM_FLAGS_GEN_BINOP): Adjust operator functions. * compile/compile-c-types.c (convert_qualified): Use enum_flags::raw. * enum-flags-selftests.c Adjust ternary operator CHECK_VALID tests. (selftests::enum_flags_tests::self_test): Add more ternary operator tests. * record-btrace.c (btrace_thread_flag_to_str): Change parameter's type to btrace_thread_flags from btrace_thread_flag. (record_btrace_cancel_resume, record_btrace_step_thread): Change local's type to btrace_thread_flags from btrace_thread_flag. Add cast in DEBUG call.
Diffstat (limited to 'gdb/enum-flags-selftests.c')
-rw-r--r--gdb/enum-flags-selftests.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/gdb/enum-flags-selftests.c b/gdb/enum-flags-selftests.c
index b4c9d875ed3..6b55110cb60 100644
--- a/gdb/enum-flags-selftests.c
+++ b/gdb/enum-flags-selftests.c
@@ -146,7 +146,7 @@ CHECK_VALID (true, RE, RE (1))
CHECK_VALID (true, RE, RE (RE2 ()))
CHECK_VALID (false, void, RE (EF2 ()))
CHECK_VALID (true, RE, RE (RE ()))
-CHECK_VALID (true, RE, RE (EF ()))
+CHECK_VALID (false, void, RE (EF ()))
/* other -> EF. */
@@ -268,23 +268,30 @@ CHECK_VALID (true, EF, ~EF ())
/* Check ternary operator. This exercises implicit conversions. */
-/* Invalid since each type can be converted to the other. */
-/* GCC 4.8 incorrectly fails to compile this test with:
- error: operands to ?: have different types ‘enum_flags<RE>’ and ‘RE’
- Confirmed to compile/pass with gcc 4.9, 5.3 and clang 3.7.
-*/
-#if GCC_VERSION >= 4009
-CHECK_VALID (false, void, true ? EF () : RE ())
-CHECK_VALID (false, void, true ? RE () : EF ())
-#endif
+CHECK_VALID (true, EF, true ? EF () : RE ())
+CHECK_VALID (true, EF, true ? RE () : EF ())
+
+/* Both enums should have the same underlying type. Pick any. */
+typedef std::underlying_type<RE>::type und;
/* These are valid, but it's not a big deal since you won't be able to
- assign the resulting int to an enum or an enum_flags without a
- cast. */
-CHECK_VALID (true, int, true ? EF () : EF2 ())
-CHECK_VALID (true, int, true ? EF2 () : EF ())
-CHECK_VALID (true, int, true ? EF () : RE2 ())
-CHECK_VALID (true, int, true ? RE2 () : EF ())
+ assign the resulting integer to an enum or an enum_flags without a
+ cast.
+
+ The latter two tests are disabled on older GCCs because they
+ incorrectly fail to compile with gcc 4.8 and 4.9 at least, with:
+
+ no known conversion from ‘enum_flags<RE>::underlying_type {aka
+ unsigned int}’ to ‘enum_flags_tests::RE2’
+
+ They've been confirmed to compile/pass with gcc 5.3, gcc 7.1 and
+ clang 3.7. */
+CHECK_VALID (true, und, true ? EF () : EF2 ())
+CHECK_VALID (true, und, true ? EF2 () : EF ())
+#if GCC_VERSION >= 5003
+CHECK_VALID (true, und, true ? EF () : RE2 ())
+CHECK_VALID (true, und, true ? RE2 () : EF ())
+#endif
/* Unfortunately this can't work due to the way C++ computes the
return type of the ternary conditional operator. int isn't
@@ -487,13 +494,34 @@ self_test ()
}
/* Check the ternary operator. */
+
{
+ /* raw enum, raw enum */
constexpr test_flags f1 = true ? FLAG1 : FLAG2;
STATIC_SELF_CHECK (f1 == FLAG1);
constexpr test_flags f2 = false ? FLAG1 : FLAG2;
STATIC_SELF_CHECK (f2 == FLAG2);
}
+ {
+ /* enum flags, raw enum */
+ constexpr test_flags src = FLAG1;
+ constexpr test_flags f1 = true ? src : FLAG2;
+ STATIC_SELF_CHECK (f1 == FLAG1);
+ constexpr test_flags f2 = false ? src : FLAG2;
+ STATIC_SELF_CHECK (f2 == FLAG2);
+ }
+
+ {
+ /* enum flags, enum flags */
+ constexpr test_flags src1 = FLAG1;
+ constexpr test_flags src2 = FLAG2;
+ constexpr test_flags f1 = true ? src1 : src2;
+ STATIC_SELF_CHECK (f1 == src1);
+ constexpr test_flags f2 = false ? src1 : src2;
+ STATIC_SELF_CHECK (f2 == src2);
+ }
+
/* Check that we can use operator| in switch cases, where only
constants are allowed. This should work because operator| is
constexpr. */