Commit | Line | Data |
---|---|---|
04902b09 PA |
1 | /* Self tests for enum-flags for GDB, the GNU debugger. |
2 | ||
3 | Copyright (C) 2016-2020 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 | /* On clang, disable -Wenum-compare due to "error: comparison of two | |
319 | values with different enumeration types [-Werror,-Wenum-compare]". | |
320 | clang doesn't suppress -Wenum-compare in SFINAE contexts. Not a | |
321 | big deal since misuses like these in GDB will be caught by -Werror | |
322 | anyway. This check is here mainly for completeness. */ | |
323 | #if defined __clang__ | |
324 | # pragma GCC diagnostic push | |
325 | # pragma GCC diagnostic ignored "-Wenum-compare" | |
326 | #endif | |
327 | CHECK_VALID (true, bool, RE () == RE2 ()) | |
328 | CHECK_VALID (true, bool, RE () != RE2 ()) | |
329 | #if defined __clang__ | |
330 | # pragma GCC diagnostic pop | |
331 | #endif | |
332 | ||
333 | CHECK_VALID (true, bool, EF (RE (1)) != EF (RE (2))) | |
334 | CHECK_VALID (true, bool, EF (RE (1)) != RE (2)) | |
335 | CHECK_VALID (true, bool, RE (1) != EF (RE (2))) | |
336 | ||
337 | CHECK_VALID (true, bool, EF () == 0) | |
338 | ||
339 | /* Check we didn't disable/delete comparison between non-flags enums | |
340 | and unrelated types by mistake. */ | |
341 | CHECK_VALID (true, bool, NF (1) == NF (1)) | |
342 | CHECK_VALID (true, bool, NF (1) == int (1)) | |
343 | CHECK_VALID (true, bool, NF (1) == char (1)) | |
344 | ||
345 | /* -------------------------------------------------------------------- */ | |
346 | ||
347 | /* Follows misc tests that exercise the API. Some are compile time, | |
348 | when possible, others are run time. */ | |
349 | ||
350 | enum test_flag | |
351 | { | |
352 | FLAG1 = 1 << 1, | |
353 | FLAG2 = 1 << 2, | |
354 | FLAG3 = 1 << 3, | |
355 | }; | |
356 | ||
357 | enum test_uflag : unsigned | |
358 | { | |
359 | UFLAG1 = 1 << 1, | |
360 | UFLAG2 = 1 << 2, | |
361 | UFLAG3 = 1 << 3, | |
362 | }; | |
363 | ||
364 | DEF_ENUM_FLAGS_TYPE (test_flag, test_flags); | |
365 | DEF_ENUM_FLAGS_TYPE (test_uflag, test_uflags); | |
366 | ||
367 | static void | |
368 | self_test () | |
369 | { | |
370 | /* Check that default construction works. */ | |
371 | { | |
372 | constexpr test_flags f; | |
373 | ||
374 | gdb_static_assert (f == 0); | |
375 | } | |
376 | ||
377 | /* Check that assignment from zero works. */ | |
378 | { | |
379 | test_flags f (FLAG1); | |
380 | ||
381 | SELF_CHECK (f == FLAG1); | |
382 | ||
383 | f = 0; | |
384 | ||
385 | SELF_CHECK (f == 0); | |
386 | } | |
387 | ||
388 | /* Check that construction from zero works. */ | |
389 | { | |
390 | constexpr test_flags zero1 = 0; | |
391 | constexpr test_flags zero2 (0); | |
392 | constexpr test_flags zero3 {0}; | |
393 | constexpr test_flags zero4 = {0}; | |
394 | ||
395 | gdb_static_assert (zero1 == 0); | |
396 | gdb_static_assert (zero2 == 0); | |
397 | gdb_static_assert (zero3 == 0); | |
398 | gdb_static_assert (zero4 == 0); | |
399 | } | |
400 | ||
401 | /* Check construction from enum value. */ | |
402 | { | |
403 | gdb_static_assert (test_flags (FLAG1) == FLAG1); | |
404 | gdb_static_assert (test_flags (FLAG2) != FLAG1); | |
405 | } | |
406 | ||
407 | /* Check copy/assignment. */ | |
408 | { | |
409 | constexpr test_flags src = FLAG1; | |
410 | ||
411 | constexpr test_flags f1 = src; | |
412 | constexpr test_flags f2 (src); | |
413 | constexpr test_flags f3 {src}; | |
414 | constexpr test_flags f4 = {src}; | |
415 | ||
416 | gdb_static_assert (f1 == FLAG1); | |
417 | gdb_static_assert (f2 == FLAG1); | |
418 | gdb_static_assert (f3 == FLAG1); | |
419 | gdb_static_assert (f4 == FLAG1); | |
420 | } | |
421 | ||
422 | /* Check moving. */ | |
423 | { | |
424 | test_flags src = FLAG1; | |
425 | test_flags dst = 0; | |
426 | ||
427 | dst = std::move (src); | |
428 | SELF_CHECK (dst == FLAG1); | |
429 | } | |
430 | ||
431 | /* Check construction from an 'or' of multiple bits. For this to | |
432 | work, operator| must be overridden to return an enum type. The | |
433 | builtin version would return int instead and then the conversion | |
434 | to test_flags would fail. */ | |
435 | { | |
436 | constexpr test_flags f = FLAG1 | FLAG2; | |
437 | gdb_static_assert (f == (FLAG1 | FLAG2)); | |
438 | } | |
439 | ||
440 | /* Similarly, check that "FLAG1 | FLAG2" on the rhs of an assignment | |
441 | operator works. */ | |
442 | { | |
443 | test_flags f = 0; | |
444 | f |= FLAG1 | FLAG2; | |
445 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
446 | ||
447 | f &= FLAG1 | FLAG2; | |
448 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
449 | ||
450 | f ^= FLAG1 | FLAG2; | |
451 | SELF_CHECK (f == 0); | |
452 | } | |
453 | ||
454 | /* Check explicit conversion to int works. */ | |
455 | { | |
456 | constexpr int some_bits (FLAG1 | FLAG2); | |
457 | ||
458 | /* And comparison with int works too. */ | |
459 | gdb_static_assert (some_bits == (FLAG1 | FLAG2)); | |
460 | gdb_static_assert (some_bits == test_flags (FLAG1 | FLAG2)); | |
461 | } | |
462 | ||
463 | /* Check operator| and operator|=. Particularly interesting is | |
464 | making sure that putting the enum value on the lhs side of the | |
465 | expression works (FLAG | f). */ | |
466 | { | |
467 | test_flags f = FLAG1; | |
468 | f |= FLAG2; | |
469 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
470 | } | |
471 | { | |
472 | test_flags f = FLAG1; | |
473 | f = f | FLAG2; | |
474 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
475 | } | |
476 | { | |
477 | test_flags f = FLAG1; | |
478 | f = FLAG2 | f; | |
479 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
480 | } | |
481 | ||
482 | /* Check the &/&= operators. */ | |
483 | { | |
484 | test_flags f = FLAG1 & FLAG2; | |
485 | SELF_CHECK (f == 0); | |
486 | ||
487 | f = FLAG1 | FLAG2; | |
488 | f &= FLAG2; | |
489 | SELF_CHECK (f == FLAG2); | |
490 | ||
491 | f = FLAG1 | FLAG2; | |
492 | f = f & FLAG2; | |
493 | SELF_CHECK (f == FLAG2); | |
494 | ||
495 | f = FLAG1 | FLAG2; | |
496 | f = FLAG2 & f; | |
497 | SELF_CHECK (f == FLAG2); | |
498 | } | |
499 | ||
500 | /* Check the ^/^= operators. */ | |
501 | { | |
502 | constexpr test_flags f = FLAG1 ^ FLAG2; | |
503 | gdb_static_assert (f == (FLAG1 ^ FLAG2)); | |
504 | } | |
505 | ||
506 | { | |
507 | test_flags f = FLAG1 ^ FLAG2; | |
508 | f ^= FLAG3; | |
509 | SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3)); | |
510 | f = f ^ FLAG3; | |
511 | SELF_CHECK (f == (FLAG1 | FLAG2)); | |
512 | f = FLAG3 ^ f; | |
513 | SELF_CHECK (f == (FLAG1 | FLAG2 | FLAG3)); | |
514 | } | |
515 | ||
516 | /* Check operator~. Note this only compiles with unsigned | |
517 | flags. */ | |
518 | { | |
519 | constexpr test_uflags f1 = ~UFLAG1; | |
520 | constexpr test_uflags f2 = ~f1; | |
521 | gdb_static_assert (f2 == UFLAG1); | |
522 | } | |
523 | ||
524 | /* Check the ternary operator. */ | |
525 | ||
526 | { | |
527 | /* raw enum, raw enum */ | |
528 | constexpr test_flags f1 = true ? FLAG1 : FLAG2; | |
529 | gdb_static_assert (f1 == FLAG1); | |
530 | constexpr test_flags f2 = false ? FLAG1 : FLAG2; | |
531 | gdb_static_assert (f2 == FLAG2); | |
532 | } | |
533 | ||
534 | { | |
535 | /* enum flags, raw enum */ | |
536 | constexpr test_flags src = FLAG1; | |
537 | constexpr test_flags f1 = true ? src : FLAG2; | |
538 | gdb_static_assert (f1 == FLAG1); | |
539 | constexpr test_flags f2 = false ? src : FLAG2; | |
540 | gdb_static_assert (f2 == FLAG2); | |
541 | } | |
542 | ||
543 | { | |
544 | /* enum flags, enum flags */ | |
545 | constexpr test_flags src1 = FLAG1; | |
546 | constexpr test_flags src2 = FLAG2; | |
547 | constexpr test_flags f1 = true ? src1 : src2; | |
548 | gdb_static_assert (f1 == src1); | |
549 | constexpr test_flags f2 = false ? src1 : src2; | |
550 | gdb_static_assert (f2 == src2); | |
551 | } | |
552 | ||
553 | /* Check that we can use flags in switch expressions (requires | |
554 | unambiguous conversion to integer). Also check that we can use | |
555 | operator| in switch cases, where only constants are allowed. | |
556 | This should work because operator| is constexpr. */ | |
557 | { | |
558 | test_flags f = FLAG1 | FLAG2; | |
559 | bool ok = false; | |
560 | ||
561 | switch (f) | |
562 | { | |
563 | case FLAG1: | |
564 | break; | |
565 | case FLAG2: | |
566 | break; | |
567 | case FLAG1 | FLAG2: | |
568 | ok = true; | |
569 | break; | |
570 | } | |
571 | ||
572 | SELF_CHECK (ok); | |
573 | } | |
574 | } | |
575 | ||
576 | } /* namespace enum_flags_tests */ | |
577 | } /* namespace selftests */ | |
578 | ||
579 | void _initialize_enum_flags_selftests (); | |
580 | ||
581 | void | |
582 | _initialize_enum_flags_selftests () | |
583 | { | |
584 | selftests::register_test ("enum-flags", | |
585 | selftests::enum_flags_tests::self_test); | |
586 | } |