1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * sparse/dissect.c
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Started by Oleg Nesterov <oleg@redhat.com>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7f08c3bdfSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
8f08c3bdfSopenharmony_ci * in the Software without restriction, including without limitation the rights
9f08c3bdfSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10f08c3bdfSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
11f08c3bdfSopenharmony_ci * furnished to do so, subject to the following conditions:
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14f08c3bdfSopenharmony_ci * all copies or substantial portions of the Software.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17f08c3bdfSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18f08c3bdfSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19f08c3bdfSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20f08c3bdfSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21f08c3bdfSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22f08c3bdfSopenharmony_ci * THE SOFTWARE.
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#include "dissect.h"
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci#define	U_VOID	 0x00
28f08c3bdfSopenharmony_ci#define	U_SELF	((1 << U_SHIFT) - 1)
29f08c3bdfSopenharmony_ci#define	U_MASK	(U_R_VAL | U_W_VAL | U_R_AOF)
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci#define	DO_LIST(l__, p__, expr__)		\
32f08c3bdfSopenharmony_ci	do {					\
33f08c3bdfSopenharmony_ci		typeof(l__->list[0]) p__;	\
34f08c3bdfSopenharmony_ci		FOR_EACH_PTR(l__, p__)		\
35f08c3bdfSopenharmony_ci			expr__;			\
36f08c3bdfSopenharmony_ci		END_FOR_EACH_PTR(p__);		\
37f08c3bdfSopenharmony_ci	} while (0)
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci#define	DO_2_LIST(l1__,l2__, p1__,p2__, expr__)	\
40f08c3bdfSopenharmony_ci	do {					\
41f08c3bdfSopenharmony_ci		typeof(l1__->list[0]) p1__;	\
42f08c3bdfSopenharmony_ci		typeof(l2__->list[0]) p2__;	\
43f08c3bdfSopenharmony_ci		PREPARE_PTR_LIST(l1__, p1__);	\
44f08c3bdfSopenharmony_ci		FOR_EACH_PTR(l2__, p2__)	\
45f08c3bdfSopenharmony_ci			expr__;			\
46f08c3bdfSopenharmony_ci			NEXT_PTR_LIST(p1__);	\
47f08c3bdfSopenharmony_ci		END_FOR_EACH_PTR(p2__);		\
48f08c3bdfSopenharmony_ci		FINISH_PTR_LIST(p1__);		\
49f08c3bdfSopenharmony_ci	} while (0)
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_citypedef unsigned usage_t;
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_cistruct symbol *dissect_ctx;
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_cistatic struct reporter *reporter;
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_cistatic void do_sym_list(struct symbol_list *list);
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_cistatic struct symbol
61f08c3bdfSopenharmony_ci	*base_type(struct symbol *sym),
62f08c3bdfSopenharmony_ci	*do_initializer(struct symbol *type, struct expression *expr),
63f08c3bdfSopenharmony_ci	*do_expression(usage_t mode, struct expression *expr),
64f08c3bdfSopenharmony_ci	*do_statement(usage_t mode, struct statement *stmt);
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_cistatic inline int is_ptr(struct symbol *type)
67f08c3bdfSopenharmony_ci{
68f08c3bdfSopenharmony_ci	return type->type == SYM_PTR || type->type == SYM_ARRAY;
69f08c3bdfSopenharmony_ci}
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_cistatic inline usage_t u_rval(usage_t mode)
72f08c3bdfSopenharmony_ci{
73f08c3bdfSopenharmony_ci	return mode & (U_R_VAL | (U_MASK << U_SHIFT))
74f08c3bdfSopenharmony_ci		? U_R_VAL : 0;
75f08c3bdfSopenharmony_ci}
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_cistatic inline usage_t u_addr(usage_t mode)
78f08c3bdfSopenharmony_ci{
79f08c3bdfSopenharmony_ci	return mode = mode & U_MASK
80f08c3bdfSopenharmony_ci		? U_R_AOF | (mode & U_W_AOF) : 0;
81f08c3bdfSopenharmony_ci}
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_cistatic usage_t u_lval(struct symbol *type)
84f08c3bdfSopenharmony_ci{
85f08c3bdfSopenharmony_ci	int wptr = is_ptr(type) && !(type->ctype.modifiers & MOD_CONST);
86f08c3bdfSopenharmony_ci	return wptr || type == &bad_ctype
87f08c3bdfSopenharmony_ci		? U_W_AOF | U_R_VAL : U_R_VAL;
88f08c3bdfSopenharmony_ci}
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_cistatic usage_t fix_mode(struct symbol *type, usage_t mode)
91f08c3bdfSopenharmony_ci{
92f08c3bdfSopenharmony_ci	mode &= (U_SELF | (U_SELF << U_SHIFT));
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci	switch (type->type) {
95f08c3bdfSopenharmony_ci		case SYM_BASETYPE:
96f08c3bdfSopenharmony_ci			if (!type->ctype.base_type)
97f08c3bdfSopenharmony_ci				break;
98f08c3bdfSopenharmony_ci		case SYM_ENUM:
99f08c3bdfSopenharmony_ci		case SYM_BITFIELD:
100f08c3bdfSopenharmony_ci			if (mode & U_MASK)
101f08c3bdfSopenharmony_ci				mode &= U_SELF;
102f08c3bdfSopenharmony_ci		default:
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci		break; case SYM_FN:
105f08c3bdfSopenharmony_ci			if (mode & U_R_VAL)
106f08c3bdfSopenharmony_ci				mode |= U_R_AOF;
107f08c3bdfSopenharmony_ci			mode &= ~(U_R_VAL | U_W_AOF);
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci		break; case SYM_ARRAY:
110f08c3bdfSopenharmony_ci			if (mode & (U_MASK << U_SHIFT))
111f08c3bdfSopenharmony_ci				mode >>= U_SHIFT;
112f08c3bdfSopenharmony_ci			else if (mode != U_W_VAL)
113f08c3bdfSopenharmony_ci				mode = u_addr(mode);
114f08c3bdfSopenharmony_ci	}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	if (!(mode & U_R_AOF))
117f08c3bdfSopenharmony_ci		mode &= ~U_W_AOF;
118f08c3bdfSopenharmony_ci
119f08c3bdfSopenharmony_ci	return mode;
120f08c3bdfSopenharmony_ci}
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_cistatic struct symbol *report_member(usage_t mode, struct position *pos,
123f08c3bdfSopenharmony_ci					struct symbol *type, struct symbol *mem)
124f08c3bdfSopenharmony_ci{
125f08c3bdfSopenharmony_ci	struct symbol *ret = mem->ctype.base_type;
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	if (mem->ident || mem->type == SYM_BAD)
128f08c3bdfSopenharmony_ci		reporter->r_member(fix_mode(ret, mode), pos, type, mem);
129f08c3bdfSopenharmony_ci
130f08c3bdfSopenharmony_ci	return ret;
131f08c3bdfSopenharmony_ci}
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_cistatic void report_implicit(usage_t mode, struct position *pos, struct symbol *type)
134f08c3bdfSopenharmony_ci{
135f08c3bdfSopenharmony_ci	if (type->type != SYM_STRUCT && type->type != SYM_UNION)
136f08c3bdfSopenharmony_ci		return;
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ci	if (type->ident != NULL)
139f08c3bdfSopenharmony_ci		reporter->r_member(mode, pos, type, NULL);
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	DO_LIST(type->symbol_list, mem,
142f08c3bdfSopenharmony_ci		report_implicit(mode, pos, base_type(mem)));
143f08c3bdfSopenharmony_ci}
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_cistatic inline struct symbol *expr_symbol(struct expression *expr)
146f08c3bdfSopenharmony_ci{
147f08c3bdfSopenharmony_ci	struct symbol *sym = expr->symbol;
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci	if (!sym) {
150f08c3bdfSopenharmony_ci		sym = lookup_symbol(expr->symbol_name, NS_SYMBOL);
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci		if (!sym) {
153f08c3bdfSopenharmony_ci			sym = alloc_symbol(expr->pos, SYM_BAD);
154f08c3bdfSopenharmony_ci			bind_symbol(sym, expr->symbol_name, NS_SYMBOL);
155f08c3bdfSopenharmony_ci			sym->kind = expr->op ?: 'v'; /* see EXPR_CALL */
156f08c3bdfSopenharmony_ci		}
157f08c3bdfSopenharmony_ci	}
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_ci	if (!sym->ctype.base_type)
160f08c3bdfSopenharmony_ci		sym->ctype.base_type = &bad_ctype;
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_ci	return sym;
163f08c3bdfSopenharmony_ci}
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_cistatic struct symbol *report_symbol(usage_t mode, struct expression *expr)
166f08c3bdfSopenharmony_ci{
167f08c3bdfSopenharmony_ci	struct symbol *sym = expr_symbol(expr);
168f08c3bdfSopenharmony_ci	struct symbol *ret = base_type(sym);
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ci	if (0 && ret->type == SYM_ENUM)
171f08c3bdfSopenharmony_ci		return report_member(mode, &expr->pos, ret, expr->symbol);
172f08c3bdfSopenharmony_ci
173f08c3bdfSopenharmony_ci	reporter->r_symbol(fix_mode(ret, mode), &expr->pos, sym);
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci	return ret;
176f08c3bdfSopenharmony_ci}
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_cistatic bool deanon(struct symbol *base, struct ident *node, struct symbol *parent)
179f08c3bdfSopenharmony_ci{
180f08c3bdfSopenharmony_ci	struct ident *pi = parent ? parent->ident : NULL;
181f08c3bdfSopenharmony_ci	char name[256];
182f08c3bdfSopenharmony_ci
183f08c3bdfSopenharmony_ci	if (!node) {
184f08c3bdfSopenharmony_ci		base->ident = pi;
185f08c3bdfSopenharmony_ci		return false;
186f08c3bdfSopenharmony_ci	}
187f08c3bdfSopenharmony_ci
188f08c3bdfSopenharmony_ci	snprintf(name, sizeof(name), "%.*s:%.*s",
189f08c3bdfSopenharmony_ci		pi ? pi->len : 0, pi ? pi->name : NULL, node->len, node->name);
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci	base->ident = built_in_ident(name);
192f08c3bdfSopenharmony_ci	return true;
193f08c3bdfSopenharmony_ci}
194f08c3bdfSopenharmony_ci
195f08c3bdfSopenharmony_cistatic void report_memdef(struct symbol *sym, struct symbol *mem)
196f08c3bdfSopenharmony_ci{
197f08c3bdfSopenharmony_ci	mem->kind = 'm';
198f08c3bdfSopenharmony_ci	if (sym && mem->ident)
199f08c3bdfSopenharmony_ci		reporter->r_memdef(sym, mem);
200f08c3bdfSopenharmony_ci}
201f08c3bdfSopenharmony_ci
202f08c3bdfSopenharmony_cistatic void examine_sym_node(struct symbol *node, struct symbol *parent)
203f08c3bdfSopenharmony_ci{
204f08c3bdfSopenharmony_ci	struct ident *name = node->ident;
205f08c3bdfSopenharmony_ci	struct symbol *base, *dctx;
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ci	if (node->visited)
208f08c3bdfSopenharmony_ci		return;
209f08c3bdfSopenharmony_ci	node->visited = 1;
210f08c3bdfSopenharmony_ci	node->kind = 'v';
211f08c3bdfSopenharmony_ci
212f08c3bdfSopenharmony_ci	while ((base = node->ctype.base_type) != NULL)
213f08c3bdfSopenharmony_ci		switch (base->type) {
214f08c3bdfSopenharmony_ci		case SYM_TYPEOF:
215f08c3bdfSopenharmony_ci			node->ctype.base_type =
216f08c3bdfSopenharmony_ci				do_expression(U_VOID, base->initializer);
217f08c3bdfSopenharmony_ci			break;
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci		case SYM_ARRAY:
220f08c3bdfSopenharmony_ci			do_expression(U_R_VAL, base->array_size);
221f08c3bdfSopenharmony_ci		case SYM_PTR:
222f08c3bdfSopenharmony_ci			node = base;
223f08c3bdfSopenharmony_ci			break;
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci		case SYM_FN:
226f08c3bdfSopenharmony_ci			node->kind = 'f';
227f08c3bdfSopenharmony_ci			node = base;
228f08c3bdfSopenharmony_ci			break;
229f08c3bdfSopenharmony_ci
230f08c3bdfSopenharmony_ci		case SYM_STRUCT: case SYM_UNION: //case SYM_ENUM:
231f08c3bdfSopenharmony_ci			if (base->inspected)
232f08c3bdfSopenharmony_ci				return;
233f08c3bdfSopenharmony_ci			base->inspected = 1;
234f08c3bdfSopenharmony_ci			base->kind = 's';
235f08c3bdfSopenharmony_ci
236f08c3bdfSopenharmony_ci			if (!base->symbol_list)
237f08c3bdfSopenharmony_ci				return;
238f08c3bdfSopenharmony_ci
239f08c3bdfSopenharmony_ci			dctx = dissect_ctx;
240f08c3bdfSopenharmony_ci			if (toplevel(base->scope))
241f08c3bdfSopenharmony_ci				dissect_ctx = NULL;
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci			if (base->ident || deanon(base, name, parent))
244f08c3bdfSopenharmony_ci				reporter->r_symdef(base);
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci			if (base->ident)
247f08c3bdfSopenharmony_ci				parent = base;
248f08c3bdfSopenharmony_ci			DO_LIST(base->symbol_list, mem,
249f08c3bdfSopenharmony_ci				examine_sym_node(mem, parent);
250f08c3bdfSopenharmony_ci				report_memdef(parent, mem));
251f08c3bdfSopenharmony_ci			dissect_ctx = dctx;
252f08c3bdfSopenharmony_ci		default:
253f08c3bdfSopenharmony_ci			return;
254f08c3bdfSopenharmony_ci		}
255f08c3bdfSopenharmony_ci}
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_cistatic struct symbol *base_type(struct symbol *sym)
258f08c3bdfSopenharmony_ci{
259f08c3bdfSopenharmony_ci	if (!sym)
260f08c3bdfSopenharmony_ci		return &bad_ctype;
261f08c3bdfSopenharmony_ci
262f08c3bdfSopenharmony_ci	if (sym->type == SYM_NODE)
263f08c3bdfSopenharmony_ci		examine_sym_node(sym, NULL);
264f08c3bdfSopenharmony_ci
265f08c3bdfSopenharmony_ci	return sym->ctype.base_type	// builtin_fn_type
266f08c3bdfSopenharmony_ci		?: &bad_ctype;
267f08c3bdfSopenharmony_ci}
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_cistatic struct symbol *__lookup_member(struct symbol *type, struct ident *name, int *p_addr)
270f08c3bdfSopenharmony_ci{
271f08c3bdfSopenharmony_ci	struct symbol *node;
272f08c3bdfSopenharmony_ci	int addr = 0;
273f08c3bdfSopenharmony_ci
274f08c3bdfSopenharmony_ci	FOR_EACH_PTR(type->symbol_list, node)
275f08c3bdfSopenharmony_ci		if (!name) {
276f08c3bdfSopenharmony_ci			if (addr == *p_addr)
277f08c3bdfSopenharmony_ci				return node;
278f08c3bdfSopenharmony_ci		}
279f08c3bdfSopenharmony_ci		else if (node->ident == NULL) {
280f08c3bdfSopenharmony_ci			node = __lookup_member(node->ctype.base_type, name, NULL);
281f08c3bdfSopenharmony_ci			if (node)
282f08c3bdfSopenharmony_ci				goto found;
283f08c3bdfSopenharmony_ci		}
284f08c3bdfSopenharmony_ci		else if (node->ident == name) {
285f08c3bdfSopenharmony_cifound:
286f08c3bdfSopenharmony_ci			if (p_addr)
287f08c3bdfSopenharmony_ci				*p_addr = addr;
288f08c3bdfSopenharmony_ci			return node;
289f08c3bdfSopenharmony_ci		}
290f08c3bdfSopenharmony_ci		addr++;
291f08c3bdfSopenharmony_ci	END_FOR_EACH_PTR(node);
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ci	return NULL;
294f08c3bdfSopenharmony_ci}
295f08c3bdfSopenharmony_ci
296f08c3bdfSopenharmony_cistatic struct symbol *lookup_member(struct symbol *type, struct ident *name, int *addr)
297f08c3bdfSopenharmony_ci{
298f08c3bdfSopenharmony_ci	struct symbol *mem = __lookup_member(type, name, addr);
299f08c3bdfSopenharmony_ci
300f08c3bdfSopenharmony_ci	if (!mem) {
301f08c3bdfSopenharmony_ci		static struct symbol bad_member = {
302f08c3bdfSopenharmony_ci			.type = SYM_BAD,
303f08c3bdfSopenharmony_ci			.ctype.base_type = &bad_ctype,
304f08c3bdfSopenharmony_ci			.kind = 'm',
305f08c3bdfSopenharmony_ci		};
306f08c3bdfSopenharmony_ci
307f08c3bdfSopenharmony_ci		if (!type->symbol_list)
308f08c3bdfSopenharmony_ci			type->scope = file_scope;
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_ci		mem = &bad_member;
311f08c3bdfSopenharmony_ci		mem->ident = name;
312f08c3bdfSopenharmony_ci	}
313f08c3bdfSopenharmony_ci
314f08c3bdfSopenharmony_ci	return mem;
315f08c3bdfSopenharmony_ci}
316f08c3bdfSopenharmony_ci
317f08c3bdfSopenharmony_cistatic struct expression *peek_preop(struct expression *expr, int op)
318f08c3bdfSopenharmony_ci{
319f08c3bdfSopenharmony_ci	do {
320f08c3bdfSopenharmony_ci		if (expr->type != EXPR_PREOP)
321f08c3bdfSopenharmony_ci			break;
322f08c3bdfSopenharmony_ci		if (expr->op == op)
323f08c3bdfSopenharmony_ci			return expr->unop;
324f08c3bdfSopenharmony_ci		if (expr->op == '(')
325f08c3bdfSopenharmony_ci			expr = expr->unop;
326f08c3bdfSopenharmony_ci		else
327f08c3bdfSopenharmony_ci			break;
328f08c3bdfSopenharmony_ci	} while (expr);
329f08c3bdfSopenharmony_ci
330f08c3bdfSopenharmony_ci	return NULL;
331f08c3bdfSopenharmony_ci}
332f08c3bdfSopenharmony_ci
333f08c3bdfSopenharmony_cistatic struct symbol *do_expression(usage_t mode, struct expression *expr)
334f08c3bdfSopenharmony_ci{
335f08c3bdfSopenharmony_ci	struct symbol *ret = &int_ctype;
336f08c3bdfSopenharmony_ci
337f08c3bdfSopenharmony_ciagain:
338f08c3bdfSopenharmony_ci	if (expr) switch (expr->type) {
339f08c3bdfSopenharmony_ci	default:
340f08c3bdfSopenharmony_ci		warning(expr->pos, "bad expr->type: %d", expr->type);
341f08c3bdfSopenharmony_ci
342f08c3bdfSopenharmony_ci	case EXPR_TYPE:		// [struct T]; Why ???
343f08c3bdfSopenharmony_ci	case EXPR_VALUE:
344f08c3bdfSopenharmony_ci	case EXPR_FVALUE:
345f08c3bdfSopenharmony_ci
346f08c3bdfSopenharmony_ci	break; case EXPR_LABEL:
347f08c3bdfSopenharmony_ci		ret = &label_ctype;
348f08c3bdfSopenharmony_ci
349f08c3bdfSopenharmony_ci	break; case EXPR_STRING:
350f08c3bdfSopenharmony_ci		ret = &string_ctype;
351f08c3bdfSopenharmony_ci
352f08c3bdfSopenharmony_ci	break; case EXPR_STATEMENT:
353f08c3bdfSopenharmony_ci		ret = do_statement(mode, expr->statement);
354f08c3bdfSopenharmony_ci
355f08c3bdfSopenharmony_ci	break; case EXPR_SIZEOF: case EXPR_ALIGNOF: case EXPR_PTRSIZEOF:
356f08c3bdfSopenharmony_ci		do_expression(U_VOID, expr->cast_expression);
357f08c3bdfSopenharmony_ci
358f08c3bdfSopenharmony_ci	break; case EXPR_COMMA:
359f08c3bdfSopenharmony_ci		do_expression(U_VOID, expr->left);
360f08c3bdfSopenharmony_ci		ret = do_expression(mode, expr->right);
361f08c3bdfSopenharmony_ci
362f08c3bdfSopenharmony_ci	break; case EXPR_CAST: case EXPR_FORCE_CAST: //case EXPR_IMPLIED_CAST:
363f08c3bdfSopenharmony_ci		ret = base_type(expr->cast_type);
364f08c3bdfSopenharmony_ci		do_initializer(ret, expr->cast_expression);
365f08c3bdfSopenharmony_ci
366f08c3bdfSopenharmony_ci	break; case EXPR_COMPARE: case EXPR_LOGICAL:
367f08c3bdfSopenharmony_ci		mode = u_rval(mode);
368f08c3bdfSopenharmony_ci		do_expression(mode, expr->left);
369f08c3bdfSopenharmony_ci		do_expression(mode, expr->right);
370f08c3bdfSopenharmony_ci
371f08c3bdfSopenharmony_ci	break; case EXPR_CONDITIONAL: //case EXPR_SELECT:
372f08c3bdfSopenharmony_ci		do_expression(expr->cond_true
373f08c3bdfSopenharmony_ci					? U_R_VAL : U_R_VAL | mode,
374f08c3bdfSopenharmony_ci				expr->conditional);
375f08c3bdfSopenharmony_ci		ret = do_expression(mode, expr->cond_true);
376f08c3bdfSopenharmony_ci		ret = do_expression(mode, expr->cond_false);
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_ci	break; case EXPR_CALL:
379f08c3bdfSopenharmony_ci		if (expr->fn->type == EXPR_SYMBOL)
380f08c3bdfSopenharmony_ci			expr->fn->op = 'f'; /* for expr_symbol() */
381f08c3bdfSopenharmony_ci		ret = do_expression(U_R_PTR, expr->fn);
382f08c3bdfSopenharmony_ci		if (is_ptr(ret))
383f08c3bdfSopenharmony_ci			ret = ret->ctype.base_type;
384f08c3bdfSopenharmony_ci		DO_2_LIST(ret->arguments, expr->args, arg, val,
385f08c3bdfSopenharmony_ci			do_expression(u_lval(base_type(arg)), val));
386f08c3bdfSopenharmony_ci		ret = ret->type == SYM_FN ? base_type(ret)
387f08c3bdfSopenharmony_ci			: &bad_ctype;
388f08c3bdfSopenharmony_ci
389f08c3bdfSopenharmony_ci	break; case EXPR_ASSIGNMENT:
390f08c3bdfSopenharmony_ci		mode |= U_W_VAL | U_R_VAL;
391f08c3bdfSopenharmony_ci		if (expr->op == '=')
392f08c3bdfSopenharmony_ci			mode &= ~U_R_VAL;
393f08c3bdfSopenharmony_ci		ret = do_expression(mode, expr->left);
394f08c3bdfSopenharmony_ci		report_implicit(mode, &expr->pos, ret);
395f08c3bdfSopenharmony_ci		mode = expr->op == '='
396f08c3bdfSopenharmony_ci			? u_lval(ret) : U_R_VAL;
397f08c3bdfSopenharmony_ci		do_expression(mode, expr->right);
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci	break; case EXPR_BINOP: {
400f08c3bdfSopenharmony_ci		struct symbol *l, *r;
401f08c3bdfSopenharmony_ci		mode |= u_rval(mode);
402f08c3bdfSopenharmony_ci		l = do_expression(mode, expr->left);
403f08c3bdfSopenharmony_ci		r = do_expression(mode, expr->right);
404f08c3bdfSopenharmony_ci		if (expr->op != '+' && expr->op != '-')
405f08c3bdfSopenharmony_ci			;
406f08c3bdfSopenharmony_ci		else if (!is_ptr_type(r))
407f08c3bdfSopenharmony_ci			ret = l;
408f08c3bdfSopenharmony_ci		else if (!is_ptr_type(l))
409f08c3bdfSopenharmony_ci			ret = r;
410f08c3bdfSopenharmony_ci	}
411f08c3bdfSopenharmony_ci
412f08c3bdfSopenharmony_ci	break; case EXPR_PREOP: case EXPR_POSTOP: {
413f08c3bdfSopenharmony_ci		struct expression *unop = expr->unop;
414f08c3bdfSopenharmony_ci
415f08c3bdfSopenharmony_ci		switch (expr->op) {
416f08c3bdfSopenharmony_ci		case SPECIAL_INCREMENT:
417f08c3bdfSopenharmony_ci		case SPECIAL_DECREMENT:
418f08c3bdfSopenharmony_ci			mode |= U_W_VAL | U_R_VAL;
419f08c3bdfSopenharmony_ci		default:
420f08c3bdfSopenharmony_ci			mode |= u_rval(mode);
421f08c3bdfSopenharmony_ci		case '(':
422f08c3bdfSopenharmony_ci			ret = do_expression(mode, unop);
423f08c3bdfSopenharmony_ci
424f08c3bdfSopenharmony_ci		break; case '&':
425f08c3bdfSopenharmony_ci			if ((expr = peek_preop(unop, '*')))
426f08c3bdfSopenharmony_ci				goto again;
427f08c3bdfSopenharmony_ci			ret = alloc_symbol(unop->pos, SYM_PTR);
428f08c3bdfSopenharmony_ci			ret->ctype.base_type =
429f08c3bdfSopenharmony_ci				do_expression(u_addr(mode), unop);
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci		break; case '*':
432f08c3bdfSopenharmony_ci			if ((expr = peek_preop(unop, '&')))
433f08c3bdfSopenharmony_ci				goto again;
434f08c3bdfSopenharmony_ci			if (mode & (U_MASK << U_SHIFT))
435f08c3bdfSopenharmony_ci				mode |= U_R_VAL;
436f08c3bdfSopenharmony_ci			mode <<= U_SHIFT;
437f08c3bdfSopenharmony_ci			if (mode & (U_R_AOF << U_SHIFT))
438f08c3bdfSopenharmony_ci				mode |= U_R_VAL;
439f08c3bdfSopenharmony_ci			if (mode & (U_W_VAL << U_SHIFT))
440f08c3bdfSopenharmony_ci				mode |= U_W_AOF;
441f08c3bdfSopenharmony_ci			ret = do_expression(mode, unop);
442f08c3bdfSopenharmony_ci			ret = is_ptr(ret) ? base_type(ret)
443f08c3bdfSopenharmony_ci				: &bad_ctype;
444f08c3bdfSopenharmony_ci		}
445f08c3bdfSopenharmony_ci	}
446f08c3bdfSopenharmony_ci
447f08c3bdfSopenharmony_ci	break; case EXPR_DEREF: {
448f08c3bdfSopenharmony_ci		struct symbol *p_type;
449f08c3bdfSopenharmony_ci		usage_t p_mode;
450f08c3bdfSopenharmony_ci
451f08c3bdfSopenharmony_ci		p_mode = mode & U_SELF;
452f08c3bdfSopenharmony_ci		if (!(mode & U_MASK) && (mode & (U_MASK << U_SHIFT)))
453f08c3bdfSopenharmony_ci			p_mode = U_R_VAL;
454f08c3bdfSopenharmony_ci		p_type = do_expression(p_mode, expr->deref);
455f08c3bdfSopenharmony_ci
456f08c3bdfSopenharmony_ci		ret = report_member(mode, &expr->pos, p_type,
457f08c3bdfSopenharmony_ci			lookup_member(p_type, expr->member, NULL));
458f08c3bdfSopenharmony_ci	}
459f08c3bdfSopenharmony_ci
460f08c3bdfSopenharmony_ci	break; case EXPR_OFFSETOF: {
461f08c3bdfSopenharmony_ci		struct symbol *in = base_type(expr->in);
462f08c3bdfSopenharmony_ci
463f08c3bdfSopenharmony_ci		do {
464f08c3bdfSopenharmony_ci			if (expr->op == '.') {
465f08c3bdfSopenharmony_ci				in = report_member(U_VOID, &expr->pos, in,
466f08c3bdfSopenharmony_ci					lookup_member(in, expr->ident, NULL));
467f08c3bdfSopenharmony_ci			} else {
468f08c3bdfSopenharmony_ci				do_expression(U_R_VAL, expr->index);
469f08c3bdfSopenharmony_ci				in = in->ctype.base_type;
470f08c3bdfSopenharmony_ci			}
471f08c3bdfSopenharmony_ci		} while ((expr = expr->down));
472f08c3bdfSopenharmony_ci	}
473f08c3bdfSopenharmony_ci
474f08c3bdfSopenharmony_ci	break; case EXPR_GENERIC: {
475f08c3bdfSopenharmony_ci		struct type_expression *map;
476f08c3bdfSopenharmony_ci
477f08c3bdfSopenharmony_ci		do_expression(U_VOID, expr->control);
478f08c3bdfSopenharmony_ci
479f08c3bdfSopenharmony_ci		for (map = expr->map; map; map = map->next)
480f08c3bdfSopenharmony_ci			ret = do_expression(mode, map->expr);
481f08c3bdfSopenharmony_ci		if (expr->def)
482f08c3bdfSopenharmony_ci			ret = do_expression(mode, expr->def);
483f08c3bdfSopenharmony_ci	}
484f08c3bdfSopenharmony_ci
485f08c3bdfSopenharmony_ci	break; case EXPR_SYMBOL:
486f08c3bdfSopenharmony_ci		ret = report_symbol(mode, expr);
487f08c3bdfSopenharmony_ci	}
488f08c3bdfSopenharmony_ci
489f08c3bdfSopenharmony_ci	return ret;
490f08c3bdfSopenharmony_ci}
491f08c3bdfSopenharmony_ci
492f08c3bdfSopenharmony_cistatic void do_asm_xputs(usage_t mode, struct asm_operand_list *xputs)
493f08c3bdfSopenharmony_ci{
494f08c3bdfSopenharmony_ci	DO_LIST(xputs, op, do_expression(U_W_AOF | mode, op->expr));
495f08c3bdfSopenharmony_ci}
496f08c3bdfSopenharmony_ci
497f08c3bdfSopenharmony_cistatic struct symbol *do_statement(usage_t mode, struct statement *stmt)
498f08c3bdfSopenharmony_ci{
499f08c3bdfSopenharmony_ci	struct symbol *ret = &void_ctype;
500f08c3bdfSopenharmony_ci
501f08c3bdfSopenharmony_ci	if (stmt) switch (stmt->type) {
502f08c3bdfSopenharmony_ci	default:
503f08c3bdfSopenharmony_ci		warning(stmt->pos, "bad stmt->type: %d", stmt->type);
504f08c3bdfSopenharmony_ci
505f08c3bdfSopenharmony_ci	case STMT_NONE:
506f08c3bdfSopenharmony_ci	case STMT_RANGE:
507f08c3bdfSopenharmony_ci	case STMT_CONTEXT:
508f08c3bdfSopenharmony_ci
509f08c3bdfSopenharmony_ci	break; case STMT_DECLARATION:
510f08c3bdfSopenharmony_ci		do_sym_list(stmt->declaration);
511f08c3bdfSopenharmony_ci
512f08c3bdfSopenharmony_ci	break; case STMT_EXPRESSION:
513f08c3bdfSopenharmony_ci		ret = do_expression(mode, stmt->expression);
514f08c3bdfSopenharmony_ci
515f08c3bdfSopenharmony_ci	break; case STMT_RETURN: {
516f08c3bdfSopenharmony_ci		struct symbol *type = dissect_ctx->ctype.base_type;
517f08c3bdfSopenharmony_ci		do_expression(u_lval(base_type(type)), stmt->expression);
518f08c3bdfSopenharmony_ci	}
519f08c3bdfSopenharmony_ci
520f08c3bdfSopenharmony_ci	break; case STMT_ASM:
521f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->asm_string);
522f08c3bdfSopenharmony_ci		do_asm_xputs(U_W_VAL, stmt->asm_outputs);
523f08c3bdfSopenharmony_ci		do_asm_xputs(U_R_VAL, stmt->asm_inputs);
524f08c3bdfSopenharmony_ci
525f08c3bdfSopenharmony_ci	break; case STMT_COMPOUND: {
526f08c3bdfSopenharmony_ci		int count;
527f08c3bdfSopenharmony_ci
528f08c3bdfSopenharmony_ci		count = statement_list_size(stmt->stmts);
529f08c3bdfSopenharmony_ci		DO_LIST(stmt->stmts, st,
530f08c3bdfSopenharmony_ci			ret = do_statement(--count ? U_VOID : mode, st));
531f08c3bdfSopenharmony_ci	}
532f08c3bdfSopenharmony_ci
533f08c3bdfSopenharmony_ci	break; case STMT_ITERATOR:
534f08c3bdfSopenharmony_ci		do_sym_list(stmt->iterator_syms);
535f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->iterator_pre_statement);
536f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->iterator_pre_condition);
537f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->iterator_post_statement);
538f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->iterator_statement);
539f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->iterator_post_condition);
540f08c3bdfSopenharmony_ci
541f08c3bdfSopenharmony_ci	break; case STMT_IF:
542f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->if_conditional);
543f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->if_true);
544f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->if_false);
545f08c3bdfSopenharmony_ci
546f08c3bdfSopenharmony_ci	break; case STMT_SWITCH:
547f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->switch_expression);
548f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->switch_statement);
549f08c3bdfSopenharmony_ci
550f08c3bdfSopenharmony_ci	break; case STMT_CASE:
551f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->case_expression);
552f08c3bdfSopenharmony_ci		do_expression(U_R_VAL, stmt->case_to);
553f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt->case_statement);
554f08c3bdfSopenharmony_ci
555f08c3bdfSopenharmony_ci	break; case STMT_GOTO:
556f08c3bdfSopenharmony_ci		do_expression(U_R_PTR, stmt->goto_expression);
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_ci	break; case STMT_LABEL:
559f08c3bdfSopenharmony_ci		do_statement(mode, stmt->label_statement);
560f08c3bdfSopenharmony_ci
561f08c3bdfSopenharmony_ci	}
562f08c3bdfSopenharmony_ci
563f08c3bdfSopenharmony_ci	return ret;
564f08c3bdfSopenharmony_ci}
565f08c3bdfSopenharmony_ci
566f08c3bdfSopenharmony_cistatic struct symbol *do_initializer(struct symbol *type, struct expression *expr)
567f08c3bdfSopenharmony_ci{
568f08c3bdfSopenharmony_ci	struct symbol *m_type;
569f08c3bdfSopenharmony_ci	struct expression *m_expr;
570f08c3bdfSopenharmony_ci	int m_addr;
571f08c3bdfSopenharmony_ci
572f08c3bdfSopenharmony_ci	if (expr) switch (expr->type) {
573f08c3bdfSopenharmony_ci	default:
574f08c3bdfSopenharmony_ci		do_expression(u_lval(type), expr);
575f08c3bdfSopenharmony_ci
576f08c3bdfSopenharmony_ci	break; case EXPR_INDEX:
577f08c3bdfSopenharmony_ci		do_initializer(base_type(type), expr->idx_expression);
578f08c3bdfSopenharmony_ci
579f08c3bdfSopenharmony_ci	break; case EXPR_INITIALIZER:
580f08c3bdfSopenharmony_ci		m_addr = 0;
581f08c3bdfSopenharmony_ci		FOR_EACH_PTR(expr->expr_list, m_expr) {
582f08c3bdfSopenharmony_ci			if (type->type == SYM_ARRAY) {
583f08c3bdfSopenharmony_ci				m_type = base_type(type);
584f08c3bdfSopenharmony_ci				if (m_expr->type == EXPR_INDEX)
585f08c3bdfSopenharmony_ci					m_expr = m_expr->idx_expression;
586f08c3bdfSopenharmony_ci			} else {
587f08c3bdfSopenharmony_ci				int *m_atop = &m_addr;
588f08c3bdfSopenharmony_ci
589f08c3bdfSopenharmony_ci				m_type = type;
590f08c3bdfSopenharmony_ci				while (m_expr->type == EXPR_IDENTIFIER) {
591f08c3bdfSopenharmony_ci					m_type = report_member(U_W_VAL, &m_expr->pos, m_type,
592f08c3bdfSopenharmony_ci							lookup_member(m_type, m_expr->expr_ident, m_atop));
593f08c3bdfSopenharmony_ci					m_expr = m_expr->ident_expression;
594f08c3bdfSopenharmony_ci					m_atop = NULL;
595f08c3bdfSopenharmony_ci				}
596f08c3bdfSopenharmony_ci
597f08c3bdfSopenharmony_ci				if (m_atop) {
598f08c3bdfSopenharmony_ci					m_type = report_member(U_W_VAL, &m_expr->pos, m_type,
599f08c3bdfSopenharmony_ci							lookup_member(m_type, NULL, m_atop));
600f08c3bdfSopenharmony_ci				}
601f08c3bdfSopenharmony_ci
602f08c3bdfSopenharmony_ci				if (m_expr->type != EXPR_INITIALIZER)
603f08c3bdfSopenharmony_ci					report_implicit(U_W_VAL, &m_expr->pos, m_type);
604f08c3bdfSopenharmony_ci			}
605f08c3bdfSopenharmony_ci			do_initializer(m_type, m_expr);
606f08c3bdfSopenharmony_ci			m_addr++;
607f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(m_expr);
608f08c3bdfSopenharmony_ci	}
609f08c3bdfSopenharmony_ci
610f08c3bdfSopenharmony_ci	return type;
611f08c3bdfSopenharmony_ci}
612f08c3bdfSopenharmony_ci
613f08c3bdfSopenharmony_cistatic inline struct symbol *do_symbol(struct symbol *sym)
614f08c3bdfSopenharmony_ci{
615f08c3bdfSopenharmony_ci	struct symbol *type = base_type(sym);
616f08c3bdfSopenharmony_ci	struct symbol *dctx = dissect_ctx;
617f08c3bdfSopenharmony_ci	struct statement *stmt;
618f08c3bdfSopenharmony_ci
619f08c3bdfSopenharmony_ci	reporter->r_symdef(sym);
620f08c3bdfSopenharmony_ci
621f08c3bdfSopenharmony_ci	switch (type->type) {
622f08c3bdfSopenharmony_ci	default:
623f08c3bdfSopenharmony_ci		if (!sym->initializer)
624f08c3bdfSopenharmony_ci			break;
625f08c3bdfSopenharmony_ci		reporter->r_symbol(U_W_VAL, &sym->pos, sym);
626f08c3bdfSopenharmony_ci		if (!dctx)
627f08c3bdfSopenharmony_ci			dissect_ctx = sym;
628f08c3bdfSopenharmony_ci		do_initializer(type, sym->initializer);
629f08c3bdfSopenharmony_ci		dissect_ctx = dctx;
630f08c3bdfSopenharmony_ci
631f08c3bdfSopenharmony_ci	break; case SYM_FN:
632f08c3bdfSopenharmony_ci		stmt = sym->ctype.modifiers & MOD_INLINE
633f08c3bdfSopenharmony_ci			? type->inline_stmt : type->stmt;
634f08c3bdfSopenharmony_ci		if (!stmt)
635f08c3bdfSopenharmony_ci			break;
636f08c3bdfSopenharmony_ci
637f08c3bdfSopenharmony_ci		if (dctx)
638f08c3bdfSopenharmony_ci			sparse_error(dctx->pos, "dissect_ctx change %s -> %s",
639f08c3bdfSopenharmony_ci				show_ident(dctx->ident), show_ident(sym->ident));
640f08c3bdfSopenharmony_ci
641f08c3bdfSopenharmony_ci		dissect_ctx = sym;
642f08c3bdfSopenharmony_ci		do_sym_list(type->arguments);
643f08c3bdfSopenharmony_ci		do_statement(U_VOID, stmt);
644f08c3bdfSopenharmony_ci		dissect_ctx = dctx;
645f08c3bdfSopenharmony_ci	}
646f08c3bdfSopenharmony_ci
647f08c3bdfSopenharmony_ci	return type;
648f08c3bdfSopenharmony_ci}
649f08c3bdfSopenharmony_ci
650f08c3bdfSopenharmony_cistatic void do_sym_list(struct symbol_list *list)
651f08c3bdfSopenharmony_ci{
652f08c3bdfSopenharmony_ci	DO_LIST(list, sym, do_symbol(sym));
653f08c3bdfSopenharmony_ci}
654f08c3bdfSopenharmony_ci
655f08c3bdfSopenharmony_civoid dissect(struct reporter *rep, struct string_list *filelist)
656f08c3bdfSopenharmony_ci{
657f08c3bdfSopenharmony_ci	reporter = rep;
658f08c3bdfSopenharmony_ci
659f08c3bdfSopenharmony_ci	DO_LIST(filelist, file, do_sym_list(__sparse(file)));
660f08c3bdfSopenharmony_ci}
661