improve entity verifier
[libfirm] / ir / tr / trverify.c
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
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
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
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
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
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
110 static bool check_primitive_type(const ir_type *tp)
111 {
112         return check_type_mode(tp);
113 }
114
115 static bool check_pointer_type(const ir_type *tp)
116 {
117         return check_type_mode(tp);
118 }
119
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
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
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
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
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 in initializer_on_wrong_irg");
197 }
198
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         } else if (entity_has_compound_ent_values(ent)) {
204                 bool   fine = true;
205                 size_t n    = get_compound_ent_n_values(ent);
206                 size_t i;
207                 for (i = 0; i < n; ++i) {
208                         fine &= constant_on_wrong_irg(get_compound_ent_value(ent, i));
209                 }
210                 return fine;
211         }
212         return true;
213 }
214
215 static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage,
216                                    const char *linkage_name)
217 {
218         bool fine = true;
219         if ((get_entity_linkage(entity) & linkage) == 0)
220                 return true;
221         if (get_entity_visibility(entity) != ir_visibility_external) {
222                 report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name);
223                 fine = false;
224         }
225         if (!entity_has_definition(entity)) {
226                 report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name);
227                 fine = false;
228         }
229         return fine;
230 }
231
232 int check_entity(const ir_entity *entity)
233 {
234         bool          fine           = true;
235         ir_type      *tp             = get_entity_type(entity);
236         ir_linkage    linkage        = get_entity_linkage(entity);
237
238         fine &= constants_on_wrong_irg(entity);
239
240         if (is_method_entity(entity)) {
241                 ir_graph *irg = get_entity_irg(entity);
242                 if (irg != NULL) {
243                         ir_entity *irg_entity = get_irg_entity(irg);
244                         if (irg_entity != entity) {
245                                 report_error("entity(%+F)->irg->entity(%+F) relation invalid",
246                                              entity, irg_entity);
247                                 fine = false;
248                         }
249                 }
250                 if (get_entity_peculiarity(entity) == peculiarity_existent) {
251                         ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(entity));
252                         if (impl == NULL) {
253                                 report_error("inherited method entity %+F must have constant pointing to existent entity.", entity);
254                                 fine = false;
255                         }
256                 }
257         }
258
259         if (linkage & IR_LINKAGE_NO_CODEGEN) {
260                 if (!is_method_entity(entity)) {
261                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity);
262                         fine = false;
263                 } else if (get_entity_irg(entity) == NULL) {
264                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity);
265                         fine = false;
266                 }
267                 if (get_entity_visibility(entity) != ir_visibility_external) {
268                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity);
269                         fine = false;
270                 }
271         }
272         check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK");
273         check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT,
274                                "GARBAGE_COLLECT");
275         check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE");
276
277         if (is_atomic_entity(entity) && entity->initializer != NULL) {
278                 ir_mode *mode = NULL;
279                 ir_initializer_t *initializer = entity->initializer;
280                 switch (initializer->kind) {
281                 case IR_INITIALIZER_CONST:
282                         mode = get_irn_mode(get_initializer_const_value(initializer));
283                         break;
284                 case IR_INITIALIZER_TARVAL:
285                         mode = get_tarval_mode(get_initializer_tarval_value(initializer));
286                         break;
287                 case IR_INITIALIZER_NULL:
288                 case IR_INITIALIZER_COMPOUND:
289                         break;
290                 }
291                 if (mode != NULL && mode != get_type_mode(tp)) {
292                         report_error("initializer of entity %+F has wrong mode.", entity);
293                         fine = false;
294                 }
295         }
296         return fine;
297 }
298
299 static void check_tore(type_or_ent tore, void *env)
300 {
301         bool *fine = (bool*)env;
302
303         if (is_type(tore.typ)) {
304                 *fine &= check_type(tore.typ);
305         } else {
306                 assert(is_entity(tore.ent));
307                 *fine &= check_entity(tore.ent);
308         }
309 }
310
311 int tr_verify(void)
312 {
313         bool          fine = true;
314         ir_type      *constructors;
315         ir_type      *destructors;
316         ir_type      *thread_locals;
317         size_t        i, n;
318         ir_segment_t  s;
319
320         type_walk(check_tore, NULL, &fine);
321
322         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
323                 const ir_type *type = get_segment_type(s);
324                 size_t         e;
325                 for (e = 0; e < get_compound_n_members(type); ++e) {
326                         ir_entity *entity = get_compound_member(type, e);
327                         if (get_entity_ld_ident(entity) == NULL &&
328                                 get_entity_visibility(entity) != ir_visibility_private) {
329                                 report_error("public segment member %+F has no name",
330                                              entity);
331                                 fine = false;
332                         }
333                 }
334         }
335
336         constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
337         for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
338                 const ir_entity *entity = get_compound_member(constructors, i);
339                 if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
340                         report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
341                                      entity);
342                         fine = false;
343                 }
344                 /* Mach-O doesn't like labels in this section */
345                 if (get_entity_ld_name(entity)[0] != '\0') {
346                         report_error("entity %+F in constructors must not have an ld_name",
347                                      entity);
348                         fine = false;
349                 }
350         }
351         destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
352         for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
353                 const ir_entity *entity = get_compound_member(destructors, i);
354                 if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
355                         report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER",
356                                      entity);
357                         fine = false;
358                 }
359                 /* Mach-O doesn't like labels in this section */
360                 if (get_entity_ld_name(entity)[0] != '\0') {
361                         report_error("entity %+F in destructors must not have an ld_name",
362                                      entity);
363                         fine = false;
364                 }
365         }
366         thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
367         for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
368                 const ir_entity *entity = get_compound_member(thread_locals, i);
369                 /* this is odd and should not be allowed I think */
370                 if (is_method_entity(entity)) {
371                         report_error("method %+F in thread local segment");
372                         fine = false;
373                 }
374                 if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
375                         report_error("entity %+F in thread local segment is constant");
376                         fine = false;
377                 }
378         }
379
380         return fine;
381 }