xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/unittests/enum-flags-selftests.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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 
25 namespace selftests {
26 namespace 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".  */
33 enum RE
34   {
35     RE_FLAG1 = 1 << 1,
36     RE_FLAG2 = 1 << 2,
37   };
38 
39 /* Another "real enum".  */
40 enum RE2
41   {
42     RE2_FLAG1 = 1 << 1,
43     RE2_FLAG2 = 1 << 2,
44   };
45 
46 /* An unsigned "real enum".  */
47 enum URE : unsigned
48   {
49     URE_FLAG1 = 1 << 1,
50     URE_FLAG2 = 1 << 2,
51     URE_FLAG3 = 0xffffffff,
52   };
53 
54 /* A non-flags enum.  */
55 enum NF
56   {
57     NF_FLAG1 = 1 << 1,
58     NF_FLAG2 = 1 << 2,
59   };
60 
61 /* The corresponding "enum flags" types.  */
62 DEF_ENUM_FLAGS_TYPE (RE, EF);
63 DEF_ENUM_FLAGS_TYPE (RE2, EF2);
64 DEF_ENUM_FLAGS_TYPE (URE, UEF);
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.  */
70 gdb_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.  */
78 static RE re ATTRIBUTE_UNUSED;
79 static 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 
93 typedef std::underlying_type<RE>::type und;
94 
95 /* Test construction / conversion from/to different types.  */
96 
97 /* RE/EF -> underlying (explicit) */
98 CHECK_VALID (true,  und,  und (RE ()))
99 CHECK_VALID (true,  und,  und (EF ()))
100 
101 /* RE/EF -> int (explicit) */
102 CHECK_VALID (true,  int,  int (RE ()))
103 CHECK_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.  */
109 CHECK_VALID (true,  RE,   RE (1))
110 CHECK_VALID (true,  RE,   RE (RE2 ()))
111 CHECK_VALID (false, void, RE (EF2 ()))
112 CHECK_VALID (true,  RE,   RE (RE ()))
113 CHECK_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.  */
121 CHECK_VALID (false, void, EF (1))
122 CHECK_VALID (false, void, EF (1u))
123 CHECK_VALID (false, void, EF (RE2 ()))
124 CHECK_VALID (false, void, EF (EF2 ()))
125 CHECK_VALID (true,  EF,   EF (RE ()))
126 CHECK_VALID (true,  EF,   EF (EF ()))
127 
128 /* Test operators.  */
129 
130 /* operator OP (raw_enum, int) */
131 
132 CHECK_VALID (false, void, RE () | 1)
133 CHECK_VALID (false, void, RE () & 1)
134 CHECK_VALID (false, void, RE () ^ 1)
135 
136 /* operator OP (int, raw_enum) */
137 
138 CHECK_VALID (false, void, 1 | RE ())
139 CHECK_VALID (false, void, 1 & RE ())
140 CHECK_VALID (false, void, 1 ^ RE ())
141 
142 /* operator OP (enum_flags, int) */
143 
144 CHECK_VALID (false, void, EF () | 1)
145 CHECK_VALID (false, void, EF () & 1)
146 CHECK_VALID (false, void, EF () ^ 1)
147 
148 /* operator OP (int, enum_flags) */
149 
150 CHECK_VALID (false, void, 1 | EF ())
151 CHECK_VALID (false, void, 1 & EF ())
152 CHECK_VALID (false, void, 1 ^ EF ())
153 
154 /* operator OP (raw_enum, raw_enum) */
155 
156 CHECK_VALID (false, void, RE () | RE2 ())
157 CHECK_VALID (false, void, RE () & RE2 ())
158 CHECK_VALID (false, void, RE () ^ RE2 ())
159 CHECK_VALID (true,  RE,   RE () | RE ())
160 CHECK_VALID (true,  RE,   RE () & RE ())
161 CHECK_VALID (true,  RE,   RE () ^ RE ())
162 
163 /* operator OP (enum_flags, raw_enum) */
164 
165 CHECK_VALID (false, void, EF () | RE2 ())
166 CHECK_VALID (false, void, EF () & RE2 ())
167 CHECK_VALID (false, void, EF () ^ RE2 ())
168 CHECK_VALID (true,  EF,   EF () | RE ())
169 CHECK_VALID (true,  EF,   EF () & RE ())
170 CHECK_VALID (true,  EF,   EF () ^ RE ())
171 
172 /* operator OP= (raw_enum, raw_enum), rvalue ref on the lhs. */
173 
174 CHECK_VALID (false, void, RE () |= RE2 ())
175 CHECK_VALID (false, void, RE () &= RE2 ())
176 CHECK_VALID (false, void, RE () ^= RE2 ())
177 CHECK_VALID (false, void, RE () |= RE ())
178 CHECK_VALID (false, void, RE () &= RE ())
179 CHECK_VALID (false, void, RE () ^= RE ())
180 
181 /* operator OP= (raw_enum, raw_enum), lvalue ref on the lhs. */
182 
183 CHECK_VALID (false, void, re |= RE2 ())
184 CHECK_VALID (false, void, re &= RE2 ())
185 CHECK_VALID (false, void, re ^= RE2 ())
186 CHECK_VALID (true,  RE&,  re |= RE ())
187 CHECK_VALID (true,  RE&,  re &= RE ())
188 CHECK_VALID (true,  RE&,  re ^= RE ())
189 
190 /* operator OP= (enum_flags, raw_enum), rvalue ref on the lhs.  */
191 
192 CHECK_VALID (false, void, EF () |= RE2 ())
193 CHECK_VALID (false, void, EF () &= RE2 ())
194 CHECK_VALID (false, void, EF () ^= RE2 ())
195 CHECK_VALID (false, void, EF () |= RE ())
196 CHECK_VALID (false, void, EF () &= RE ())
197 CHECK_VALID (false, void, EF () ^= RE ())
198 
199 /* operator OP= (enum_flags, raw_enum), lvalue ref on the lhs.  */
200 
201 CHECK_VALID (false, void, ef |= RE2 ())
202 CHECK_VALID (false, void, ef &= RE2 ())
203 CHECK_VALID (false, void, ef ^= RE2 ())
204 CHECK_VALID (true,  EF&,  ef |= EF ())
205 CHECK_VALID (true,  EF&,  ef &= EF ())
206 CHECK_VALID (true,  EF&,  ef ^= EF ())
207 
208 /* operator OP= (enum_flags, enum_flags), rvalue ref on the lhs.  */
209 
210 CHECK_VALID (false, void, EF () |= EF2 ())
211 CHECK_VALID (false, void, EF () &= EF2 ())
212 CHECK_VALID (false, void, EF () ^= EF2 ())
213 CHECK_VALID (false, void, EF () |= EF ())
214 CHECK_VALID (false, void, EF () &= EF ())
215 CHECK_VALID (false, void, EF () ^= EF ())
216 
217 /* operator OP= (enum_flags, enum_flags), lvalue ref on the lhs.  */
218 
219 CHECK_VALID (false, void, ef |= EF2 ())
220 CHECK_VALID (false, void, ef &= EF2 ())
221 CHECK_VALID (false, void, ef ^= EF2 ())
222 CHECK_VALID (true,  EF&,  ef |= EF ())
223 CHECK_VALID (true,  EF&,  ef &= EF ())
224 CHECK_VALID (true,  EF&,  ef ^= EF ())
225 
226 /* operator~ (raw_enum) */
227 
228 CHECK_VALID (false,  void,   ~RE ())
229 CHECK_VALID (true,   URE,    ~URE ())
230 
231 /* operator~ (enum_flags) */
232 
233 CHECK_VALID (false,  void,   ~EF ())
234 CHECK_VALID (true,   UEF,    ~UEF ())
235 
236 /* Check ternary operator.  This exercises implicit conversions.  */
237 
238 CHECK_VALID (true,  EF,   true ? EF () : RE ())
239 CHECK_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 
254 CHECK_VALID (true,  int,  true ? EF () : EF2 ())
255 CHECK_VALID (true,  int,  true ? EF2 () : EF ())
256 #if GCC_VERSION >= 5003 || defined __clang__
257 CHECK_VALID (true,  int,  true ? EF () : RE2 ())
258 CHECK_VALID (true,  int,  true ? RE2 () : EF ())
259 #endif
260 
261 /* Same, but with an unsigned enum.  */
262 
263 typedef unsigned int uns;
264 
265 CHECK_VALID (true,  uns,  true ? EF () : UEF ())
266 CHECK_VALID (true,  uns,  true ? UEF () : EF ())
267 #if GCC_VERSION >= 5003 || defined __clang__
268 CHECK_VALID (true,  uns,  true ? EF () : URE ())
269 CHECK_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__
283 CHECK_VALID (false, void, true ? EF () : 0)
284 CHECK_VALID (false, void, true ? 0 : EF ())
285 #endif
286 
287 /* Check that the ++/--/<</>>/<<=/>>= operators are deleted.  */
288 
289 CHECK_VALID (false, void, RE ()++)
290 CHECK_VALID (false, void, ++RE ())
291 CHECK_VALID (false, void, --RE ())
292 CHECK_VALID (false, void, RE ()--)
293 
294 CHECK_VALID (false, void, RE () << 1)
295 CHECK_VALID (false, void, RE () >> 1)
296 CHECK_VALID (false, void, EF () << 1)
297 CHECK_VALID (false, void, EF () >> 1)
298 
299 CHECK_VALID (false, void, RE () <<= 1)
300 CHECK_VALID (false, void, RE () >>= 1)
301 CHECK_VALID (false, void, EF () <<= 1)
302 CHECK_VALID (false, void, EF () >>= 1)
303 
304 /* Test comparison operators.  */
305 
306 CHECK_VALID (false, void, EF () == EF2 ())
307 CHECK_VALID (false, void, EF () == RE2 ())
308 CHECK_VALID (false, void, RE () == EF2 ())
309 
310 CHECK_VALID (true,  bool, EF (RE (1)) == EF (RE (1)))
311 CHECK_VALID (true,  bool, EF (RE (1)) == RE (1))
312 CHECK_VALID (true,  bool, RE (1)      == EF (RE (1)))
313 
314 CHECK_VALID (false, void, EF () != EF2 ())
315 CHECK_VALID (false, void, EF () != RE2 ())
316 CHECK_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
337 CHECK_VALID (true,  bool, RE () == RE2 ())
338 CHECK_VALID (true,  bool, RE () != RE2 ())
339 #if defined __GNUC__
340 # pragma GCC diagnostic pop
341 #endif
342 
343 CHECK_VALID (true,  bool, EF (RE (1)) != EF (RE (2)))
344 CHECK_VALID (true,  bool, EF (RE (1)) != RE (2))
345 CHECK_VALID (true,  bool, RE (1)      != EF (RE (2)))
346 
347 CHECK_VALID (true,  bool, EF () == 0)
348 
349 /* Check we didn't disable/delete comparison between non-flags enums
350    and unrelated types by mistake.  */
351 CHECK_VALID (true,  bool, NF (1) == NF (1))
352 CHECK_VALID (true,  bool, NF (1) == int (1))
353 CHECK_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 
360 enum test_flag
361   {
362     FLAG1 = 1 << 1,
363     FLAG2 = 1 << 2,
364     FLAG3 = 1 << 3,
365   };
366 
367 enum test_uflag : unsigned
368   {
369     UFLAG1 = 1 << 1,
370     UFLAG2 = 1 << 2,
371     UFLAG3 = 1 << 3,
372   };
373 
374 DEF_ENUM_FLAGS_TYPE (test_flag, test_flags);
375 DEF_ENUM_FLAGS_TYPE (test_uflag, test_uflags);
376 
377 static void
378 self_test ()
379 {
380   /* Check that default construction works.  */
381   {
382     constexpr test_flags f;
383 
384     gdb_static_assert (f == 0);
385   }
386 
387   /* Check that assignment from zero works.  */
388   {
389     test_flags f (FLAG1);
390 
391     SELF_CHECK (f == FLAG1);
392 
393     f = 0;
394 
395     SELF_CHECK (f == 0);
396   }
397 
398   /* Check that construction from zero works.  */
399   {
400     constexpr test_flags zero1 = 0;
401     constexpr test_flags zero2 (0);
402     constexpr test_flags zero3 {0};
403     constexpr test_flags zero4 = {0};
404 
405     gdb_static_assert (zero1 == 0);
406     gdb_static_assert (zero2 == 0);
407     gdb_static_assert (zero3 == 0);
408     gdb_static_assert (zero4 == 0);
409   }
410 
411   /* Check construction from enum value.  */
412   {
413     gdb_static_assert (test_flags (FLAG1) == FLAG1);
414     gdb_static_assert (test_flags (FLAG2) != FLAG1);
415   }
416 
417   /* Check copy/assignment.  */
418   {
419     constexpr test_flags src = FLAG1;
420 
421     constexpr test_flags f1 = src;
422     constexpr test_flags f2 (src);
423     constexpr test_flags f3 {src};
424     constexpr test_flags f4 = {src};
425 
426     gdb_static_assert (f1 == FLAG1);
427     gdb_static_assert (f2 == FLAG1);
428     gdb_static_assert (f3 == FLAG1);
429     gdb_static_assert (f4 == FLAG1);
430   }
431 
432   /* Check moving.  */
433   {
434     test_flags src = FLAG1;
435     test_flags dst = 0;
436 
437     dst = std::move (src);
438     SELF_CHECK (dst == FLAG1);
439   }
440 
441   /* Check construction from an 'or' of multiple bits.  For this to
442      work, operator| must be overridden to return an enum type.  The
443      builtin version would return int instead and then the conversion
444      to test_flags would fail.  */
445   {
446     constexpr test_flags f = FLAG1 | FLAG2;
447     gdb_static_assert (f == (FLAG1 | FLAG2));
448   }
449 
450   /* Similarly, check that "FLAG1 | FLAG2" on the rhs of an assignment
451      operator works.  */
452   {
453     test_flags f = 0;
454     f |= FLAG1 | FLAG2;
455     SELF_CHECK (f == (FLAG1 | FLAG2));
456 
457     f &= FLAG1 | FLAG2;
458     SELF_CHECK (f == (FLAG1 | FLAG2));
459 
460     f ^= FLAG1 | FLAG2;
461     SELF_CHECK (f == 0);
462   }
463 
464   /* Check explicit conversion to int works.  */
465   {
466     constexpr int some_bits (FLAG1 | FLAG2);
467 
468     /* And comparison with int works too.  */
469     gdb_static_assert (some_bits == (FLAG1 | FLAG2));
470     gdb_static_assert (some_bits == test_flags (FLAG1 | FLAG2));
471   }
472 
473   /* Check operator| and operator|=.  Particularly interesting is
474      making sure that putting the enum value on the lhs side of the
475      expression works (FLAG | f).  */
476   {
477     test_flags f = FLAG1;
478     f |= FLAG2;
479     SELF_CHECK (f == (FLAG1 | FLAG2));
480   }
481   {
482     test_flags f = FLAG1;
483     f = f | FLAG2;
484     SELF_CHECK (f == (FLAG1 | FLAG2));
485   }
486   {
487     test_flags f = FLAG1;
488     f = FLAG2 | f;
489     SELF_CHECK (f == (FLAG1 | FLAG2));
490   }
491 
492   /* Check the &/&= operators.  */
493   {
494     test_flags f = FLAG1 & FLAG2;
495     SELF_CHECK (f == 0);
496 
497     f = FLAG1 | FLAG2;
498     f &= FLAG2;
499     SELF_CHECK (f == FLAG2);
500 
501     f = FLAG1 | FLAG2;
502     f = f & FLAG2;
503     SELF_CHECK (f == FLAG2);
504 
505     f = FLAG1 | FLAG2;
506     f = FLAG2 & f;
507     SELF_CHECK (f == FLAG2);
508   }
509 
510   /* Check the ^/^= operators.  */
511   {
512     constexpr test_flags f = FLAG1 ^ FLAG2;
513     gdb_static_assert (f == (FLAG1 ^ FLAG2));
514   }
515 
516   {
517     test_flags f = FLAG1 ^ FLAG2;
518     f ^= FLAG3;
519     SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3));
520     f = f ^ FLAG3;
521     SELF_CHECK (f == (FLAG1 | FLAG2));
522     f = FLAG3 ^ f;
523     SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3));
524   }
525 
526   /* Check operator~.  Note this only compiles with unsigned
527      flags.  */
528   {
529     constexpr test_uflags f1 = ~UFLAG1;
530     constexpr test_uflags f2 = ~f1;
531     gdb_static_assert (f2 == UFLAG1);
532   }
533 
534   /* Check the ternary operator.  */
535 
536   {
537     /* raw enum, raw enum */
538     constexpr test_flags f1 = true ? FLAG1 : FLAG2;
539     gdb_static_assert (f1 == FLAG1);
540     constexpr test_flags f2 = false ? FLAG1 : FLAG2;
541     gdb_static_assert (f2 == FLAG2);
542   }
543 
544   {
545     /* enum flags, raw enum */
546     constexpr test_flags src = FLAG1;
547     constexpr test_flags f1 = true ? src : FLAG2;
548     gdb_static_assert (f1 == FLAG1);
549     constexpr test_flags f2 = false ? src : FLAG2;
550     gdb_static_assert (f2 == FLAG2);
551   }
552 
553   {
554     /* enum flags, enum flags */
555     constexpr test_flags src1 = FLAG1;
556     constexpr test_flags src2 = FLAG2;
557     constexpr test_flags f1 = true ? src1 : src2;
558     gdb_static_assert (f1 == src1);
559     constexpr test_flags f2 = false ? src1 : src2;
560     gdb_static_assert (f2 == src2);
561   }
562 
563   /* Check that we can use flags in switch expressions (requires
564      unambiguous conversion to integer).  Also check that we can use
565      operator| in switch cases, where only constants are allowed.
566      This should work because operator| is constexpr.  */
567   {
568     test_flags f = FLAG1 | FLAG2;
569     bool ok = false;
570 
571     switch (f)
572       {
573       case FLAG1:
574 	break;
575       case FLAG2:
576 	break;
577       case FLAG1 | FLAG2:
578 	ok = true;
579 	break;
580       }
581 
582     SELF_CHECK (ok);
583   }
584 }
585 
586 } /* namespace enum_flags_tests */
587 } /* namespace selftests */
588 
589 void _initialize_enum_flags_selftests ();
590 
591 void
592 _initialize_enum_flags_selftests ()
593 {
594   selftests::register_test ("enum-flags",
595 			    selftests::enum_flags_tests::self_test);
596 }
597