c11_generic_expression.c revision 1.17 1 1.17 rillig /* $NetBSD: c11_generic_expression.c,v 1.17 2023/07/07 19:45:22 rillig Exp $ */
2 1.1 rillig # 3 "c11_generic_expression.c"
3 1.1 rillig
4 1.17 rillig /* lint1-extra-flags: -X 351 */
5 1.17 rillig
6 1.1 rillig /*
7 1.1 rillig * C99 added support for type-generic macros, but these were limited to the
8 1.1 rillig * header <tgmath.h>. C11 made this feature generally available.
9 1.1 rillig *
10 1.1 rillig * The generic selection is typically used with macros, but since lint1 works
11 1.1 rillig * on the preprocessed source, the test cases look a bit strange.
12 1.1 rillig *
13 1.14 rillig * C11 6.5.1.1 "Generic selection"
14 1.1 rillig */
15 1.1 rillig
16 1.16 rillig /* lint1-extra-flags: -Ac11 */
17 1.1 rillig
18 1.1 rillig /*
19 1.1 rillig * The type of 'var' is not compatible with any of the types from the
20 1.1 rillig * generic-association. This is a compile-time error.
21 1.1 rillig */
22 1.1 rillig const char *
23 1.2 rillig classify_type_without_default(double var)
24 1.1 rillig {
25 1.12 rillig /* expect-2: warning: argument 'var' unused in function 'classify_type_without_default' [231] */
26 1.3 rillig
27 1.1 rillig return _Generic(var,
28 1.1 rillig long double: "long double",
29 1.1 rillig long long: "long long",
30 1.1 rillig unsigned: "unsigned"
31 1.1 rillig );
32 1.12 rillig /* expect-1: warning: function 'classify_type_without_default' expects to return value [214] */
33 1.1 rillig }
34 1.1 rillig
35 1.1 rillig /*
36 1.1 rillig * In this case, the 'default' expression is selected.
37 1.1 rillig */
38 1.1 rillig const char *
39 1.2 rillig classify_type_with_default(double var)
40 1.1 rillig {
41 1.12 rillig /* expect-2: warning: argument 'var' unused in function 'classify_type_with_default' [231] */
42 1.3 rillig
43 1.1 rillig return _Generic(var,
44 1.1 rillig long double: "long double",
45 1.1 rillig long long: "long long",
46 1.1 rillig unsigned: "unsigned",
47 1.1 rillig default: "unknown"
48 1.1 rillig );
49 1.1 rillig }
50 1.2 rillig
51 1.2 rillig /*
52 1.2 rillig * The type of a _Generic expression is the one from the selected association.
53 1.2 rillig */
54 1.2 rillig const char *
55 1.2 rillig classify_char(char c)
56 1.2 rillig {
57 1.12 rillig /* expect-2: warning: argument 'c' unused in function 'classify_char' [231] */
58 1.3 rillig
59 1.2 rillig return _Generic(c,
60 1.2 rillig char: "yes",
61 1.2 rillig default: 0.0
62 1.2 rillig );
63 1.2 rillig }
64 1.4 rillig
65 1.4 rillig /*
66 1.4 rillig * Before cgram.y 1.238 from 2021-06-27, lint accepted a comma-expression,
67 1.4 rillig * which looked as if _Generic would accept multiple arguments before the
68 1.4 rillig * selection.
69 1.4 rillig */
70 1.4 rillig /* ARGSUSED */
71 1.4 rillig const int *
72 1.4 rillig comma_expression(char first, double second)
73 1.4 rillig {
74 1.11 rillig /* expect+1: error: syntax error 'second' [249] */
75 1.11 rillig return _Generic(first, second,
76 1.4 rillig char: "first",
77 1.4 rillig double: 2.0
78 1.4 rillig );
79 1.13 rillig /* expect+1: warning: function 'comma_expression' falls off bottom without returning value [217] */
80 1.4 rillig }
81 1.6 rillig
82 1.6 rillig /*
83 1.6 rillig * Ensure that assignment-expressions are accepted by the grammar, as
84 1.6 rillig * opposed to comma-expressions.
85 1.6 rillig */
86 1.6 rillig /* ARGSUSED */
87 1.6 rillig int
88 1.6 rillig assignment_expression(int first, int second)
89 1.6 rillig {
90 1.6 rillig return _Generic(first = second,
91 1.6 rillig int: second = first
92 1.6 rillig );
93 1.6 rillig }
94 1.7 rillig
95 1.7 rillig int
96 1.7 rillig primary_expression(void)
97 1.7 rillig {
98 1.7 rillig return _Generic(0, int: assignment_expression)(0, 0);
99 1.7 rillig }
100 1.9 rillig
101 1.9 rillig /*
102 1.9 rillig * The types don't match, therefore build_generic_selection returns NULL,
103 1.9 rillig * which is then silently ignored by init_expr. This situation is already
104 1.9 rillig * covered by the compilers, so there is no need for lint to double-check it.
105 1.9 rillig */
106 1.9 rillig const char *x = _Generic(
107 1.10 rillig 1ULL + 1.0f,
108 1.9 rillig int: 1
109 1.9 rillig );
110