GDB (xrefs)
Loading...
Searching...
No Matches
enum-flags-selftests.c
Go to the documentation of this file.
1/* Self tests for enum-flags for GDB, the GNU debugger.
2
3 Copyright (C) 2016-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "gdbsupport/enum-flags.h"
22#include "gdbsupport/valid-expr.h"
23#include "gdbsupport/selftest.h"
24
25namespace selftests {
26namespace enum_flags_tests {
27
28/* The (real) enum types used in CHECK_VALID. Their names match the
29 template parameter names of the templates defined by CHECK_VALID to
30 make it simpler to use. They could be named differently. */
31
32/* A "real enum". */
33enum RE
34 {
35 RE_FLAG1 = 1 << 1,
36 RE_FLAG2 = 1 << 2,
37 };
38
39/* Another "real enum". */
40enum RE2
41 {
42 RE2_FLAG1 = 1 << 1,
43 RE2_FLAG2 = 1 << 2,
44 };
45
46/* An unsigned "real enum". */
47enum URE : unsigned
48 {
49 URE_FLAG1 = 1 << 1,
50 URE_FLAG2 = 1 << 2,
51 URE_FLAG3 = 0xffffffff,
52 };
53
54/* A non-flags enum. */
55enum NF
56 {
57 NF_FLAG1 = 1 << 1,
58 NF_FLAG2 = 1 << 2,
59 };
60
61/* The corresponding "enum flags" types. */
65
66#if HAVE_IS_TRIVIALLY_COPYABLE
67
68/* So that std::vectors of types that have enum_flags fields can
69 reallocate efficiently memcpy. */
70gdb_static_assert (std::is_trivially_copyable<EF>::value);
71
72#endif
73
74/* A couple globals used as lvalues in the CHECK_VALID expressions
75 below. Their names (and types) match the uppercase type names
76 exposed by CHECK_VALID just to make the expressions easier to
77 follow. */
79static EF ef ATTRIBUTE_UNUSED;
80
81/* First, compile-time tests that:
82
83 - make sure that incorrect operations with mismatching enum types
84 are caught at compile time.
85
86 - make sure that the same operations but involving the right enum
87 types do compile and that they return the correct type.
88*/
89
90#define CHECK_VALID(VALID, EXPR_TYPE, EXPR) \
91 CHECK_VALID_EXPR_6 (EF, RE, EF2, RE2, UEF, URE, VALID, EXPR_TYPE, EXPR)
92
93typedef std::underlying_type<RE>::type und;
94
95/* Test construction / conversion from/to different types. */
96
97/* RE/EF -> underlying (explicit) */
98CHECK_VALID (true, und, und (RE ()))
99CHECK_VALID (true, und, und (EF ()))
100
101/* RE/EF -> int (explicit) */
102CHECK_VALID (true, int, int (RE ()))
103CHECK_VALID (true, int, int (EF ()))
104
105/* other -> RE */
106
107/* You can construct a raw enum value from an int explicitly to punch
108 a hole in the type system if need to. */
109CHECK_VALID (true, RE, RE (1))
110CHECK_VALID (true, RE, RE (RE2 ()))
111CHECK_VALID (false, void, RE (EF2 ()))
112CHECK_VALID (true, RE, RE (RE ()))
113CHECK_VALID (false, void, RE (EF ()))
114
115/* other -> EF. */
116
117/* As expected, enum-flags is a stronger type than the backing raw
118 enum. Unlike with raw enums, you can't construct an enum flags
119 from an integer nor from an unrelated enum type explicitly. Add an
120 intermediate conversion via the raw enum if you really need it. */
121CHECK_VALID (false, void, EF (1))
122CHECK_VALID (false, void, EF (1u))
123CHECK_VALID (false, void, EF (RE2 ()))
124CHECK_VALID (false, void, EF (EF2 ()))
125CHECK_VALID (true, EF, EF (RE ()))
126CHECK_VALID (true, EF, EF (EF ()))
127
128/* Test operators. */
129
130/* operator OP (raw_enum, int) */
131
132CHECK_VALID (false, void, RE () | 1)
133CHECK_VALID (false, void, RE () & 1)
134CHECK_VALID (false, void, RE () ^ 1)
135
136/* operator OP (int, raw_enum) */
137
138CHECK_VALID (false, void, 1 | RE ())
139CHECK_VALID (false, void, 1 & RE ())
140CHECK_VALID (false, void, 1 ^ RE ())
141
142/* operator OP (enum_flags, int) */
143
144CHECK_VALID (false, void, EF () | 1)
145CHECK_VALID (false, void, EF () & 1)
146CHECK_VALID (false, void, EF () ^ 1)
147
148/* operator OP (int, enum_flags) */
149
150CHECK_VALID (false, void, 1 | EF ())
151CHECK_VALID (false, void, 1 & EF ())
152CHECK_VALID (false, void, 1 ^ EF ())
153
154/* operator OP (raw_enum, raw_enum) */
155
156CHECK_VALID (false, void, RE () | RE2 ())
157CHECK_VALID (false, void, RE () & RE2 ())
158CHECK_VALID (false, void, RE () ^ RE2 ())
159CHECK_VALID (true, RE, RE () | RE ())
160CHECK_VALID (true, RE, RE () & RE ())
161CHECK_VALID (true, RE, RE () ^ RE ())
162
163/* operator OP (enum_flags, raw_enum) */
164
165CHECK_VALID (false, void, EF () | RE2 ())
166CHECK_VALID (false, void, EF () & RE2 ())
167CHECK_VALID (false, void, EF () ^ RE2 ())
168CHECK_VALID (true, EF, EF () | RE ())
169CHECK_VALID (true, EF, EF () & RE ())
170CHECK_VALID (true, EF, EF () ^ RE ())
171
172/* operator OP= (raw_enum, raw_enum), rvalue ref on the lhs. */
173
174CHECK_VALID (false, void, RE () |= RE2 ())
175CHECK_VALID (false, void, RE () &= RE2 ())
176CHECK_VALID (false, void, RE () ^= RE2 ())
177CHECK_VALID (false, void, RE () |= RE ())
178CHECK_VALID (false, void, RE () &= RE ())
179CHECK_VALID (false, void, RE () ^= RE ())
180
181/* operator OP= (raw_enum, raw_enum), lvalue ref on the lhs. */
182
183CHECK_VALID (false, void, re |= RE2 ())
184CHECK_VALID (false, void, re &= RE2 ())
185CHECK_VALID (false, void, re ^= RE2 ())
186CHECK_VALID (true, RE&, re |= RE ())
187CHECK_VALID (true, RE&, re &= RE ())
188CHECK_VALID (true, RE&, re ^= RE ())
189
190/* operator OP= (enum_flags, raw_enum), rvalue ref on the lhs. */
191
192CHECK_VALID (false, void, EF () |= RE2 ())
193CHECK_VALID (false, void, EF () &= RE2 ())
194CHECK_VALID (false, void, EF () ^= RE2 ())
195CHECK_VALID (false, void, EF () |= RE ())
196CHECK_VALID (false, void, EF () &= RE ())
197CHECK_VALID (false, void, EF () ^= RE ())
198
199/* operator OP= (enum_flags, raw_enum), lvalue ref on the lhs. */
200
201CHECK_VALID (false, void, ef |= RE2 ())
202CHECK_VALID (false, void, ef &= RE2 ())
203CHECK_VALID (false, void, ef ^= RE2 ())
204CHECK_VALID (true, EF&, ef |= EF ())
205CHECK_VALID (true, EF&, ef &= EF ())
206CHECK_VALID (true, EF&, ef ^= EF ())
207
208/* operator OP= (enum_flags, enum_flags), rvalue ref on the lhs. */
209
210CHECK_VALID (false, void, EF () |= EF2 ())
211CHECK_VALID (false, void, EF () &= EF2 ())
212CHECK_VALID (false, void, EF () ^= EF2 ())
213CHECK_VALID (false, void, EF () |= EF ())
214CHECK_VALID (false, void, EF () &= EF ())
215CHECK_VALID (false, void, EF () ^= EF ())
216
217/* operator OP= (enum_flags, enum_flags), lvalue ref on the lhs. */
218
219CHECK_VALID (false, void, ef |= EF2 ())
220CHECK_VALID (false, void, ef &= EF2 ())
221CHECK_VALID (false, void, ef ^= EF2 ())
222CHECK_VALID (true, EF&, ef |= EF ())
223CHECK_VALID (true, EF&, ef &= EF ())
224CHECK_VALID (true, EF&, ef ^= EF ())
225
226/* operator~ (raw_enum) */
227
228CHECK_VALID (false, void, ~RE ())
229CHECK_VALID (true, URE, ~URE ())
230
231/* operator~ (enum_flags) */
232
233CHECK_VALID (false, void, ~EF ())
234CHECK_VALID (true, UEF, ~UEF ())
235
236/* Check ternary operator. This exercises implicit conversions. */
237
238CHECK_VALID (true, EF, true ? EF () : RE ())
239CHECK_VALID (true, EF, true ? RE () : EF ())
240
241/* These are valid, but it's not a big deal since you won't be able to
242 assign the resulting integer to an enum or an enum_flags without a
243 cast.
244
245 The latter two tests are disabled on older GCCs because they
246 incorrectly fail with gcc 4.8 and 4.9 at least. Running the test
247 outside a SFINAE context shows:
248
249 invalid user-defined conversion from ‘EF’ to ‘RE2’
250
251 They've been confirmed to compile/pass with gcc 5.3, gcc 7.1 and
252 clang 3.7. */
253
254CHECK_VALID (true, int, true ? EF () : EF2 ())
255CHECK_VALID (true, int, true ? EF2 () : EF ())
256#if GCC_VERSION >= 5003 || defined __clang__
257CHECK_VALID (true, int, true ? EF () : RE2 ())
258CHECK_VALID (true, int, true ? RE2 () : EF ())
259#endif
260
261/* Same, but with an unsigned enum. */
262
263typedef unsigned int uns;
264
265CHECK_VALID (true, uns, true ? EF () : UEF ())
266CHECK_VALID (true, uns, true ? UEF () : EF ())
267#if GCC_VERSION >= 5003 || defined __clang__
268CHECK_VALID (true, uns, true ? EF () : URE ())
269CHECK_VALID (true, uns, true ? URE () : EF ())
270#endif
271
272/* Unfortunately this can't work due to the way C++ computes the
273 return type of the ternary conditional operator. int isn't
274 implicitly convertible to the raw enum type, so the type of the
275 expression is int. And then int is not implicitly convertible to
276 enum_flags.
277
278 GCC 4.8 fails to compile this test with:
279 error: operands to ?: have different types ‘enum_flags<RE>’ and ‘int’
280 Confirmed to work with gcc 4.9, 5.3 and clang 3.7.
281*/
282#if GCC_VERSION >= 4009 || defined __clang__
283CHECK_VALID (false, void, true ? EF () : 0)
284CHECK_VALID (false, void, true ? 0 : EF ())
285#endif
286
287/* Check that the ++/--/<</>>/<<=/>>= operators are deleted. */
288
289CHECK_VALID (false, void, RE ()++)
290CHECK_VALID (false, void, ++RE ())
291CHECK_VALID (false, void, --RE ())
292CHECK_VALID (false, void, RE ()--)
293
294CHECK_VALID (false, void, RE () << 1)
295CHECK_VALID (false, void, RE () >> 1)
296CHECK_VALID (false, void, EF () << 1)
297CHECK_VALID (false, void, EF () >> 1)
298
299CHECK_VALID (false, void, RE () <<= 1)
300CHECK_VALID (false, void, RE () >>= 1)
301CHECK_VALID (false, void, EF () <<= 1)
302CHECK_VALID (false, void, EF () >>= 1)
303
304/* Test comparison operators. */
305
306CHECK_VALID (false, void, EF () == EF2 ())
307CHECK_VALID (false, void, EF () == RE2 ())
308CHECK_VALID (false, void, RE () == EF2 ())
309
310CHECK_VALID (true, bool, EF (RE (1)) == EF (RE (1)))
311CHECK_VALID (true, bool, EF (RE (1)) == RE (1))
312CHECK_VALID (true, bool, RE (1) == EF (RE (1)))
313
314CHECK_VALID (false, void, EF () != EF2 ())
315CHECK_VALID (false, void, EF () != RE2 ())
316CHECK_VALID (false, void, RE () != EF2 ())
317
318/* Disable -Wenum-compare due to:
319
320 Clang:
321
322 "error: comparison of two values with different enumeration types
323 [-Werror,-Wenum-compare]"
324
325 GCC:
326
327 "error: comparison between ‘enum selftests::enum_flags_tests::RE’
328 and ‘enum selftests::enum_flags_tests::RE2’
329 [-Werror=enum-compare]"
330
331 Not a big deal since misuses like these in GDB will be caught by
332 -Werror anyway. This check is here mainly for completeness. */
333#if defined __GNUC__
334# pragma GCC diagnostic push
335# pragma GCC diagnostic ignored "-Wenum-compare"
336#endif
337CHECK_VALID (true, bool, RE () == RE2 ())
338CHECK_VALID (true, bool, RE () != RE2 ())
339#if defined __GNUC__
340# pragma GCC diagnostic pop
341#endif
342
343CHECK_VALID (true, bool, EF (RE (1)) != EF (RE (2)))
344CHECK_VALID (true, bool, EF (RE (1)) != RE (2))
345CHECK_VALID (true, bool, RE (1) != EF (RE (2)))
346
347CHECK_VALID (true, bool, EF () == 0)
348
349/* Check we didn't disable/delete comparison between non-flags enums
350 and unrelated types by mistake. */
351CHECK_VALID (true, bool, NF (1) == NF (1))
352CHECK_VALID (true, bool, NF (1) == int (1))
353CHECK_VALID (true, bool, NF (1) == char (1))
354
355/* -------------------------------------------------------------------- */
356
357/* Follows misc tests that exercise the API. Some are compile time,
358 when possible, others are run time. */
359
360enum test_flag
361 {
362 FLAG1 = 1 << 0,
363 FLAG2 = 1 << 1,
364 FLAG3 = 1 << 2,
365 FLAG4 = 1 << 3,
366 };
367
368enum test_uflag : unsigned
369 {
370 UFLAG1 = 1 << 0,
371 UFLAG2 = 1 << 1,
372 UFLAG3 = 1 << 2,
373 UFLAG4 = 1 << 3,
374 };
375
376DEF_ENUM_FLAGS_TYPE (test_flag, test_flags);
378
379/* to_string enumerator->string mapping functions used to test
380 enum_flags::to_string. These intentionally miss mapping a couple
381 enumerators each (xFLAG2, xFLAG4). */
382
383static std::string
385{
386 static constexpr test_flags::string_mapping mapping[] = {
387 MAP_ENUM_FLAG (FLAG1),
388 MAP_ENUM_FLAG (FLAG3),
389 };
390 return flags.to_string (mapping);
391}
392
393static std::string
395{
396 static constexpr test_uflags::string_mapping mapping[] = {
397 MAP_ENUM_FLAG (UFLAG1),
398 MAP_ENUM_FLAG (UFLAG3),
399 };
400 return flags.to_string (mapping);
401}
402
403static void
405{
406 /* Check that default construction works. */
407 {
408 constexpr test_flags f;
409
410 gdb_static_assert (f == 0);
411 }
412
413 /* Check that assignment from zero works. */
414 {
415 test_flags f (FLAG1);
416
417 SELF_CHECK (f == FLAG1);
418
419 f = 0;
420
421 SELF_CHECK (f == 0);
422 }
423
424 /* Check that construction from zero works. */
425 {
426 constexpr test_flags zero1 = 0;
427 constexpr test_flags zero2 (0);
428 constexpr test_flags zero3 {0};
429 constexpr test_flags zero4 = {0};
430
431 gdb_static_assert (zero1 == 0);
432 gdb_static_assert (zero2 == 0);
433 gdb_static_assert (zero3 == 0);
434 gdb_static_assert (zero4 == 0);
435 }
436
437 /* Check construction from enum value. */
438 {
439 gdb_static_assert (test_flags (FLAG1) == FLAG1);
440 gdb_static_assert (test_flags (FLAG2) != FLAG1);
441 }
442
443 /* Check copy/assignment. */
444 {
445 constexpr test_flags src = FLAG1;
446
447 constexpr test_flags f1 = src;
448 constexpr test_flags f2 (src);
449 constexpr test_flags f3 {src};
450 constexpr test_flags f4 = {src};
451
452 gdb_static_assert (f1 == FLAG1);
453 gdb_static_assert (f2 == FLAG1);
454 gdb_static_assert (f3 == FLAG1);
455 gdb_static_assert (f4 == FLAG1);
456 }
457
458 /* Check moving. */
459 {
460 test_flags src = FLAG1;
461 test_flags dst = 0;
462
463 dst = std::move (src);
464 SELF_CHECK (dst == FLAG1);
465 }
466
467 /* Check construction from an 'or' of multiple bits. For this to
468 work, operator| must be overridden to return an enum type. The
469 builtin version would return int instead and then the conversion
470 to test_flags would fail. */
471 {
472 constexpr test_flags f = FLAG1 | FLAG2;
473 gdb_static_assert (f == (FLAG1 | FLAG2));
474 }
475
476 /* Similarly, check that "FLAG1 | FLAG2" on the rhs of an assignment
477 operator works. */
478 {
479 test_flags f = 0;
480 f |= FLAG1 | FLAG2;
481 SELF_CHECK (f == (FLAG1 | FLAG2));
482
483 f &= FLAG1 | FLAG2;
484 SELF_CHECK (f == (FLAG1 | FLAG2));
485
486 f ^= FLAG1 | FLAG2;
487 SELF_CHECK (f == 0);
488 }
489
490 /* Check explicit conversion to int works. */
491 {
492 constexpr int some_bits (FLAG1 | FLAG2);
493
494 /* And comparison with int works too. */
495 gdb_static_assert (some_bits == (FLAG1 | FLAG2));
496 gdb_static_assert (some_bits == test_flags (FLAG1 | FLAG2));
497 }
498
499 /* Check operator| and operator|=. Particularly interesting is
500 making sure that putting the enum value on the lhs side of the
501 expression works (FLAG | f). */
502 {
503 test_flags f = FLAG1;
504 f |= FLAG2;
505 SELF_CHECK (f == (FLAG1 | FLAG2));
506 }
507 {
508 test_flags f = FLAG1;
509 f = f | FLAG2;
510 SELF_CHECK (f == (FLAG1 | FLAG2));
511 }
512 {
513 test_flags f = FLAG1;
514 f = FLAG2 | f;
515 SELF_CHECK (f == (FLAG1 | FLAG2));
516 }
517
518 /* Check the &/&= operators. */
519 {
520 test_flags f = FLAG1 & FLAG2;
521 SELF_CHECK (f == 0);
522
523 f = FLAG1 | FLAG2;
524 f &= FLAG2;
525 SELF_CHECK (f == FLAG2);
526
527 f = FLAG1 | FLAG2;
528 f = f & FLAG2;
529 SELF_CHECK (f == FLAG2);
530
531 f = FLAG1 | FLAG2;
532 f = FLAG2 & f;
533 SELF_CHECK (f == FLAG2);
534 }
535
536 /* Check the ^/^= operators. */
537 {
538 constexpr test_flags f = FLAG1 ^ FLAG2;
539 gdb_static_assert (f == (FLAG1 ^ FLAG2));
540 }
541
542 {
543 test_flags f = FLAG1 ^ FLAG2;
544 f ^= FLAG3;
545 SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3));
546 f = f ^ FLAG3;
547 SELF_CHECK (f == (FLAG1 | FLAG2));
548 f = FLAG3 ^ f;
549 SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3));
550 }
551
552 /* Check operator~. Note this only compiles with unsigned
553 flags. */
554 {
555 constexpr test_uflags f1 = ~UFLAG1;
556 constexpr test_uflags f2 = ~f1;
558 }
559
560 /* Check the ternary operator. */
561
562 {
563 /* raw enum, raw enum */
564 constexpr test_flags f1 = true ? FLAG1 : FLAG2;
565 gdb_static_assert (f1 == FLAG1);
566 constexpr test_flags f2 = false ? FLAG1 : FLAG2;
567 gdb_static_assert (f2 == FLAG2);
568 }
569
570 {
571 /* enum flags, raw enum */
572 constexpr test_flags src = FLAG1;
573 constexpr test_flags f1 = true ? src : FLAG2;
574 gdb_static_assert (f1 == FLAG1);
575 constexpr test_flags f2 = false ? src : FLAG2;
576 gdb_static_assert (f2 == FLAG2);
577 }
578
579 {
580 /* enum flags, enum flags */
581 constexpr test_flags src1 = FLAG1;
582 constexpr test_flags src2 = FLAG2;
583 constexpr test_flags f1 = true ? src1 : src2;
584 gdb_static_assert (f1 == src1);
585 constexpr test_flags f2 = false ? src1 : src2;
586 gdb_static_assert (f2 == src2);
587 }
588
589 /* Check that we can use flags in switch expressions (requires
590 unambiguous conversion to integer). Also check that we can use
591 operator| in switch cases, where only constants are allowed.
592 This should work because operator| is constexpr. */
593 {
594 test_flags f = FLAG1 | FLAG2;
595 bool ok = false;
596
597 switch (f)
598 {
599 case FLAG1:
600 break;
601 case FLAG2:
602 break;
603 case FLAG1 | FLAG2:
604 ok = true;
605 break;
606 }
607
608 SELF_CHECK (ok);
609 }
610
611 /* Check string conversion. */
612 {
613 SELF_CHECK (to_string_uflags (0)
614 == "0x0 []");
615 SELF_CHECK (to_string_uflags (UFLAG1)
616 == "0x1 [UFLAG1]");
617 SELF_CHECK (to_string_uflags (UFLAG1 | UFLAG3)
618 == "0x5 [UFLAG1 UFLAG3]");
619 SELF_CHECK (to_string_uflags (UFLAG1 | UFLAG2 | UFLAG3)
620 == "0x7 [UFLAG1 UFLAG3 0x2]");
621 SELF_CHECK (to_string_uflags (UFLAG2)
622 == "0x2 [0x2]");
623 /* Check that even with multiple unmapped flags, we only print one
624 unmapped hex number (0xa, in this case). */
625 SELF_CHECK (to_string_uflags (UFLAG1 | UFLAG2 | UFLAG3 | UFLAG4)
626 == "0xf [UFLAG1 UFLAG3 0xa]");
627
628 SELF_CHECK (to_string_flags (0)
629 == "0x0 []");
630 SELF_CHECK (to_string_flags (FLAG1)
631 == "0x1 [FLAG1]");
632 SELF_CHECK (to_string_flags (FLAG1 | FLAG3)
633 == "0x5 [FLAG1 FLAG3]");
634 SELF_CHECK (to_string_flags (FLAG1 | FLAG2 | FLAG3)
635 == "0x7 [FLAG1 FLAG3 0x2]");
636 SELF_CHECK (to_string_flags (FLAG2)
637 == "0x2 [0x2]");
638 SELF_CHECK (to_string_flags (FLAG1 | FLAG2 | FLAG3 | FLAG4)
639 == "0xf [FLAG1 FLAG3 0xa]");
640 }
641}
642
643} /* namespace enum_flags_tests */
644} /* namespace selftests */
645
647
648void
650{
651 selftests::register_test ("enum-flags",
653}
if(!(yy_init))
Definition ada-lex.c:1109
gdb_static_assert(sizeof(splay_tree_key) >=sizeof(CORE_ADDR *))
void f()
Definition 1.cc:36
static void push(int indent, string_file *stream, ULONGEST l)
void _initialize_enum_flags_selftests()
#define CHECK_VALID(VALID, EXPR_TYPE, EXPR)
mach_port_t kern_return_t mach_port_t mach_msg_type_name_t msgportsPoly mach_port_t kern_return_t pid_t pid mach_port_t kern_return_t mach_port_t task mach_port_t kern_return_t int flags
Definition gnu-nat.c:1861
static std::string to_string_flags(test_flags flags)
static std::string to_string_uflags(test_uflags flags)
std::underlying_type< RE >::type und