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