ckbool.c revision 1.6 1 /* $NetBSD: ckbool.c,v 1.6 2021/07/02 21:22:26 rillig Exp $ */
2
3 /*-
4 * Copyright (c) 2021 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland Illig <rillig (at) NetBSD.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35
36 #include <sys/cdefs.h>
37
38 #if defined(__RCSID) && !defined(lint)
39 __RCSID("$NetBSD: ckbool.c,v 1.6 2021/07/02 21:22:26 rillig Exp $");
40 #endif
41
42 #include <string.h>
43
44 #include "lint1.h"
45
46
47 /*
48 * The option -T treats _Bool as incompatible with all other scalar types.
49 * See d_c99_bool_strict.c for the exact rules and for examples.
50 */
51
52 static const char *
53 op_name(op_t op)
54 {
55 return modtab[op].m_name;
56 }
57
58 /*
59 * See if in strict bool mode, the operator takes either two bool operands
60 * or two arbitrary other operands.
61 */
62 static bool
63 is_assignment_bool_or_other(op_t op)
64 {
65 return op == ASSIGN ||
66 op == ANDASS || op == XORASS || op == ORASS ||
67 op == RETURN || op == INIT || op == FARG;
68 }
69
70 static bool
71 is_symmetric_bool_or_other(op_t op)
72 {
73 return op == EQ || op == NE ||
74 op == BITAND || op == BITXOR || op == BITOR ||
75 op == COLON;
76 }
77
78 static bool
79 is_int_constant_zero(const tnode_t *tn, tspec_t t)
80 {
81 return t == INT && tn->tn_op == CON && tn->tn_val->v_quad == 0;
82 }
83
84 static bool
85 is_typeok_strict_bool_binary(op_t op,
86 const tnode_t *ln, tspec_t lt,
87 const tnode_t *rn, tspec_t rt)
88 {
89 if ((lt == BOOL) == (rt == BOOL))
90 return true;
91
92 if ((ln->tn_from_system_header || rn->tn_from_system_header) &&
93 (is_int_constant_zero(ln, lt) || is_int_constant_zero(rn, rt)))
94 return true;
95
96 if (is_assignment_bool_or_other(op)) {
97 return lt != BOOL &&
98 (ln->tn_from_system_header || rn->tn_from_system_header);
99 }
100
101 return !is_symmetric_bool_or_other(op);
102 }
103
104 /*
105 * Some operators require that either both operands are bool or both are
106 * scalar.
107 *
108 * Code that passes this check can be compiled in a pre-C99 environment that
109 * doesn't implement the special rule C99 6.3.1.2, without silent change in
110 * behavior.
111 */
112 static bool
113 typeok_strict_bool_binary_compatible(op_t op, int arg,
114 const tnode_t *ln, tspec_t lt,
115 const tnode_t *rn, tspec_t rt)
116 {
117 if (is_typeok_strict_bool_binary(op, ln, lt, rn, rt))
118 return true;
119
120 if (op == FARG) {
121 /* argument #%d expects '%s', gets passed '%s' */
122 error(334, arg, tspec_name(lt), tspec_name(rt));
123 } else if (op == RETURN) {
124 /* return value type mismatch (%s) and (%s) */
125 error(211, tspec_name(lt), tspec_name(rt));
126 } else {
127 /* operands of '%s' have incompatible types (%s != %s) */
128 error(107, op_name(op), tspec_name(lt), tspec_name(rt));
129 }
130
131 return false;
132 }
133
134 /*
135 * In strict bool mode, check whether the types of the operands match the
136 * operator.
137 */
138 bool
139 typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
140 const tnode_t *ln,
141 const tnode_t *rn)
142
143 {
144 tspec_t lt, rt;
145
146 ln = before_conversion(ln);
147 lt = ln->tn_type->t_tspec;
148
149 if (rn != NULL) {
150 rn = before_conversion(rn);
151 rt = rn->tn_type->t_tspec;
152 } else {
153 rt = NOTSPEC;
154 }
155
156 if (rn != NULL &&
157 !typeok_strict_bool_binary_compatible(op, arg, ln, lt, rn, rt))
158 return false;
159
160 if (mp->m_requires_bool || op == QUEST) {
161 bool binary = mp->m_binary;
162 bool lbool = is_typeok_bool_operand(ln);
163 bool ok = true;
164
165 if (!binary && !lbool) {
166 /* operand of '%s' must be bool, not '%s' */
167 error(330, op_name(op), tspec_name(lt));
168 ok = false;
169 }
170 if (binary && !lbool) {
171 /* left operand of '%s' must be bool, not '%s' */
172 error(331, op_name(op), tspec_name(lt));
173 ok = false;
174 }
175 if (binary && op != QUEST && !is_typeok_bool_operand(rn)) {
176 /* right operand of '%s' must be bool, not '%s' */
177 error(332, op_name(op), tspec_name(rt));
178 ok = false;
179 }
180 return ok;
181 }
182
183 if (!mp->m_takes_bool) {
184 bool binary = mp->m_binary;
185 bool lbool = ln->tn_type->t_tspec == BOOL;
186 bool ok = true;
187
188 if (!binary && lbool) {
189 /* operand of '%s' must not be bool */
190 error(335, op_name(op));
191 ok = false;
192 }
193 if (binary && lbool) {
194 /* left operand of '%s' must not be bool */
195 error(336, op_name(op));
196 ok = false;
197 }
198 if (binary && rn->tn_type->t_tspec == BOOL) {
199 /* right operand of '%s' must not be bool */
200 error(337, op_name(op));
201 ok = false;
202 }
203 return ok;
204 }
205
206 return true;
207 }
208
209 /*
210 * See if the node is valid as operand of an operator that compares its
211 * argument with 0.
212 */
213 bool
214 is_typeok_bool_operand(const tnode_t *tn)
215 {
216 tspec_t t;
217
218 lint_assert(Tflag);
219
220 tn = before_conversion(tn);
221 t = tn->tn_type->t_tspec;
222
223 if (t == BOOL)
224 return true;
225
226 if (tn->tn_from_system_header && is_scalar(t))
227 return true;
228
229 /* For enums that are used as bit sets, allow "flags & FLAG". */
230 if (tn->tn_op == BITAND &&
231 tn->tn_left->tn_op == CVT &&
232 tn->tn_left->tn_type->t_is_enum &&
233 tn->tn_right->tn_type->t_is_enum)
234 return true;
235
236 return false;
237 }
238
239 bool
240 fallback_symbol_strict_bool(sym_t *sym)
241 {
242 if (Tflag && strcmp(sym->s_name, "__lint_false") == 0) {
243 sym->s_scl = CTCONST; /* close enough */
244 sym->s_type = gettyp(BOOL);
245 sym->s_value.v_tspec = BOOL;
246 sym->s_value.v_unsigned_since_c90 = false;
247 sym->s_value.v_quad = 0;
248 return true;
249 }
250
251 if (Tflag && strcmp(sym->s_name, "__lint_true") == 0) {
252 sym->s_scl = CTCONST; /* close enough */
253 sym->s_type = gettyp(BOOL);
254 sym->s_value.v_tspec = BOOL;
255 sym->s_value.v_unsigned_since_c90 = false;
256 sym->s_value.v_quad = 1;
257 return true;
258 }
259
260 return false;
261 }
262