1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19 
20 /**
21  * @file    tr_inheritance.c
22  * @brief   Check types and entities for correctness.
23  * @date    29.1.2003
24  * @author  Michael Beck, Goetz Lindenmaier
25  */
26 #include "config.h"
27 
28 #include "irgraph_t.h"
29 #include "irflag_t.h"
30 #include "irprintf.h"
31 #include "irgwalk.h"
32 #include "error.h"
33 #include "tv.h"
34 #include "ircons.h"
35 
report_error(const char * fmt,...)36 static void report_error(const char *fmt, ...)
37 {
38 	va_list ap;
39 
40 	fprintf(stderr, "Verify warning: ");
41 	va_start(ap, fmt);
42 	ir_vfprintf(stderr, fmt, ap);
43 	va_end(ap);
44 	fputc('\n', stderr);
45 }
46 
check_class_member(const ir_type * tp,const ir_entity * entity)47 static bool check_class_member(const ir_type *tp, const ir_entity *entity)
48 {
49 	bool fine = true;
50 	if (get_entity_n_overwrites(entity) > get_class_n_supertypes(tp)) {
51 		report_error("member %+F of %+F has too many overwrites", entity, tp);
52 		fine = false;
53 	}
54 	return fine;
55 }
56 
check_compound_type(const ir_type * tp)57 static bool check_compound_type(const ir_type *tp)
58 {
59 	bool   fine     = true;
60 	bool   is_class = is_Class_type(tp);
61 	size_t n        = get_compound_n_members(tp);
62 	size_t i;
63 
64 	for (i = 0; i < n; ++i) {
65 		ir_entity *member = get_compound_member(tp, i);
66 		ir_type   *owner;
67 
68 		if (member == NULL) {
69 			report_error("%+F has a NULL member\n", tp);
70 			fine = false;
71 			continue;
72 		}
73 		owner = get_entity_owner(member);
74 		if (owner != tp) {
75 			report_error("member %+F of %+F has owner %+F\n", member, tp, owner);
76 			fine = false;
77 		}
78 		if (is_class) {
79 			fine &= check_class_member(tp, member);
80 		}
81 	}
82 	return fine;
83 }
84 
check_array_type(const ir_type * tp)85 static bool check_array_type(const ir_type *tp)
86 {
87 	bool   fine  = true;
88 	size_t n_dim = get_array_n_dimensions(tp);
89 	size_t i;
90 
91 	for (i = 0; i < n_dim; ++i) {
92 		if (!has_array_lower_bound(tp, i) && !has_array_upper_bound(tp, i)) {
93 			report_error("missing array bound in %+F in dimension %zu", tp, i);
94 			fine = false;
95 		}
96 	}
97 	return fine;
98 }
99 
check_type_mode(const ir_type * tp)100 static bool check_type_mode(const ir_type *tp)
101 {
102 	bool fine = true;
103 	if (get_type_mode(tp) == NULL) {
104 		report_error("type %+F has no mode", tp);
105 		fine = false;
106 	}
107 	return fine;
108 }
109 
check_primitive_type(const ir_type * tp)110 static bool check_primitive_type(const ir_type *tp)
111 {
112 	return check_type_mode(tp);
113 }
114 
check_pointer_type(const ir_type * tp)115 static bool check_pointer_type(const ir_type *tp)
116 {
117 	return check_type_mode(tp);
118 }
119 
check_type(const ir_type * tp)120 int check_type(const ir_type *tp)
121 {
122 	switch (get_type_tpop_code(tp)) {
123 	case tpo_union:
124 	case tpo_struct:
125 	case tpo_class:     return check_compound_type(tp);
126 	case tpo_array:     return check_array_type(tp);
127 	case tpo_primitive: return check_primitive_type(tp);
128 	case tpo_pointer:   return check_pointer_type(tp);
129 	case tpo_enumeration:
130 	case tpo_method:
131 	case tpo_uninitialized:
132 	case tpo_unknown:
133 	case tpo_none:
134 	case tpo_code:
135 		break;
136 	}
137 	return true;
138 }
139 
check_visited_flag(ir_graph * irg,ir_node * n)140 static bool check_visited_flag(ir_graph *irg, ir_node *n)
141 {
142 	bool fine = true;
143 	if (get_irn_visited(n) > get_irg_visited(irg)) {
144 		report_error("visited flag of %+F is larger than that of corresponding irg %+F", n, irg);
145 		fine = false;
146 	}
147 	return fine;
148 }
149 
150 typedef struct myenv {
151 	ir_graph *irg;
152 	bool      fine;
153 } myenv;
154 
on_irg_storage(ir_node * n,void * data)155 static void on_irg_storage(ir_node *n, void *data)
156 {
157 	myenv *env = (myenv*)data;
158 
159 	/* We also test whether the setting of the visited flag is legal. */
160 	env->fine &= node_is_in_irgs_storage(env->irg, n);
161 	env->fine &= check_visited_flag(env->irg, n);
162 }
163 
constant_on_wrong_irg(ir_node * n)164 static bool constant_on_wrong_irg(ir_node *n)
165 {
166 	myenv env;
167 
168 	env.fine = true;
169 	env.irg  = get_const_code_irg();
170 
171 	irg_walk(n, on_irg_storage, NULL, (void *)&env);
172 	return env.fine;
173 }
174 
initializer_constant_on_wrong_irg(const ir_initializer_t * initializer)175 static bool initializer_constant_on_wrong_irg(const ir_initializer_t *initializer)
176 {
177 	switch (get_initializer_kind(initializer)) {
178 	case IR_INITIALIZER_NULL:
179 		return 0;
180 	case IR_INITIALIZER_TARVAL:
181 		return 0;
182 	case IR_INITIALIZER_CONST:
183 		return constant_on_wrong_irg(get_initializer_const_value(initializer));
184 	case IR_INITIALIZER_COMPOUND: {
185 		bool   fine = true;
186 		size_t n    = get_initializer_compound_n_entries(initializer);
187 		size_t i;
188 		for (i = 0; i < n; ++i) {
189 			const ir_initializer_t *sub
190 				= get_initializer_compound_value(initializer, i);
191 			fine &= initializer_constant_on_wrong_irg(sub);
192 		}
193 		return fine;
194 	}
195 	}
196 	panic("invalid initializer");
197 }
198 
constants_on_wrong_irg(const ir_entity * ent)199 static bool constants_on_wrong_irg(const ir_entity *ent)
200 {
201 	if (ent->initializer != NULL) {
202 		return initializer_constant_on_wrong_irg(ent->initializer);
203 	}
204 	return true;
205 }
206 
check_external_linkage(const ir_entity * entity,ir_linkage linkage,const char * linkage_name)207 static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage,
208                                    const char *linkage_name)
209 {
210 	bool fine = true;
211 	if ((get_entity_linkage(entity) & linkage) == 0)
212 		return true;
213 	if (get_entity_visibility(entity) != ir_visibility_external) {
214 		report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name);
215 		fine = false;
216 	}
217 	if (!entity_has_definition(entity)) {
218 		report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name);
219 		fine = false;
220 	}
221 	return fine;
222 }
223 
check_entity(const ir_entity * entity)224 int check_entity(const ir_entity *entity)
225 {
226 	bool          fine           = true;
227 	ir_type      *tp             = get_entity_type(entity);
228 	ir_linkage    linkage        = get_entity_linkage(entity);
229 
230 	fine &= constants_on_wrong_irg(entity);
231 
232 	if (is_method_entity(entity)) {
233 		ir_graph *irg = get_entity_irg(entity);
234 		if (irg != NULL) {
235 			ir_entity *irg_entity = get_irg_entity(irg);
236 			if (irg_entity != entity) {
237 				report_error("entity(%+F)->irg->entity(%+F) relation invalid",
238 				             entity, irg_entity);
239 				fine = false;
240 			}
241 		}
242 		if (get_entity_peculiarity(entity) == peculiarity_existent) {
243 			ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(entity));
244 			if (impl == NULL) {
245 				report_error("inherited method entity %+F must have constant pointing to existent entity.", entity);
246 				fine = false;
247 			}
248 		}
249 	}
250 
251 	if (linkage & IR_LINKAGE_NO_CODEGEN) {
252 		if (!is_method_entity(entity)) {
253 			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity);
254 			fine = false;
255 		} else if (get_entity_irg(entity) == NULL) {
256 			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity);
257 			fine = false;
258 		}
259 		if (get_entity_visibility(entity) != ir_visibility_external) {
260 			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity);
261 			fine = false;
262 		}
263 	}
264 	check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK");
265 	check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT,
266 	                       "GARBAGE_COLLECT");
267 	check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE");
268 
269 	if (is_atomic_entity(entity) && entity->initializer != NULL) {
270 		ir_mode *mode = NULL;
271 		ir_initializer_t *initializer = entity->initializer;
272 		switch (initializer->kind) {
273 		case IR_INITIALIZER_CONST:
274 			mode = get_irn_mode(get_initializer_const_value(initializer));
275 			break;
276 		case IR_INITIALIZER_TARVAL:
277 			mode = get_tarval_mode(get_initializer_tarval_value(initializer));
278 			break;
279 		case IR_INITIALIZER_NULL:
280 		case IR_INITIALIZER_COMPOUND:
281 			break;
282 		}
283 		if (mode != NULL && mode != get_type_mode(tp)) {
284 			report_error("initializer of entity %+F has wrong mode.", entity);
285 			fine = false;
286 		}
287 	}
288 	return fine;
289 }
290 
check_tore(type_or_ent tore,void * env)291 static void check_tore(type_or_ent tore, void *env)
292 {
293 	bool *fine = (bool*)env;
294 
295 	if (is_type(tore.typ)) {
296 		*fine &= check_type(tore.typ);
297 	} else {
298 		assert(is_entity(tore.ent));
299 		*fine &= check_entity(tore.ent);
300 	}
301 }
302 
tr_verify(void)303 int tr_verify(void)
304 {
305 	bool          fine = true;
306 	ir_type      *constructors;
307 	ir_type      *destructors;
308 	ir_type      *thread_locals;
309 	size_t        i, n;
310 	ir_segment_t  s;
311 
312 	type_walk(check_tore, NULL, &fine);
313 
314 	for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
315 		const ir_type *type = get_segment_type(s);
316 		size_t         e;
317 		for (e = 0; e < get_compound_n_members(type); ++e) {
318 			ir_entity *entity = get_compound_member(type, e);
319 			if (get_entity_ld_ident(entity) == NULL &&
320 				get_entity_visibility(entity) != ir_visibility_private) {
321 				report_error("public segment member %+F has no name",
322 				             entity);
323 				fine = false;
324 			}
325 		}
326 	}
327 
328 	constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
329 	for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
330 		const ir_entity *entity = get_compound_member(constructors, i);
331 		if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
332 			report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
333 			             entity);
334 			fine = false;
335 		}
336 		/* Mach-O doesn't like labels in this section */
337 		if (get_entity_ld_name(entity)[0] != '\0') {
338 			report_error("entity %+F in constructors must not have an ld_name",
339 			             entity);
340 			fine = false;
341 		}
342 	}
343 	destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
344 	for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
345 		const ir_entity *entity = get_compound_member(destructors, i);
346 		if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
347 			report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER",
348 			             entity);
349 			fine = false;
350 		}
351 		/* Mach-O doesn't like labels in this section */
352 		if (get_entity_ld_name(entity)[0] != '\0') {
353 			report_error("entity %+F in destructors must not have an ld_name",
354 			             entity);
355 			fine = false;
356 		}
357 	}
358 	thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
359 	for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
360 		const ir_entity *entity = get_compound_member(thread_locals, i);
361 		/* this is odd and should not be allowed I think */
362 		if (is_method_entity(entity)) {
363 			report_error("method %+F in thread local segment");
364 			fine = false;
365 		}
366 		if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
367 			report_error("entity %+F in thread local segment is constant");
368 			fine = false;
369 		}
370 	}
371 
372 	return fine;
373 }
374