]>
Commit | Line | Data |
---|---|---|
84a43794 MS |
1 | /* RunTime Type Identification |
2 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. | |
6b5fbb55 | 3 | Mostly written by Jason Merrill (jason@cygnus.com). |
84a43794 MS |
4 | |
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | ||
23 | #include "config.h" | |
24 | #include "tree.h" | |
25 | #include "cp-tree.h" | |
26 | #include "flags.h" | |
27 | #include "output.h" | |
28 | ||
29 | #undef NULL | |
30 | #define NULL 0 | |
31 | ||
32 | extern tree define_function (); | |
33 | extern tree build_t_desc_overload (); | |
34 | extern struct obstack *permanent_obstack; | |
35 | ||
6b5fbb55 MS |
36 | tree type_info_type_node; |
37 | tree tinfo_fn_id; | |
38 | tree tinfo_fn_type; | |
39 | ||
84a43794 MS |
40 | /* in c-common.c */ |
41 | extern tree combine_strings PROTO((tree)); | |
42 | \f | |
6b5fbb55 MS |
43 | void |
44 | init_rtti_processing () | |
45 | { | |
46 | type_info_type_node = xref_tag | |
47 | (class_type_node, get_identifier ("type_info"), NULL_TREE, 1); | |
48 | tinfo_fn_id = get_identifier ("__tf"); | |
49 | tinfo_fn_type = build_function_type | |
50 | (build_reference_type (build_type_variant (type_info_type_node, 1, 0)), | |
51 | void_list_node); | |
52 | } | |
53 | ||
54 | /* Given a pointer to an object with at least one virtual table | |
55 | pointer somewhere, return a pointer to a possible sub-object that | |
56 | has a virtual table pointer in it that is the vtable parent for | |
57 | that sub-object. */ | |
58 | static tree | |
59 | build_headof_sub (exp) | |
60 | tree exp; | |
61 | { | |
62 | tree type = TREE_TYPE (TREE_TYPE (exp)); | |
63 | tree basetype = CLASSTYPE_RTTI (type); | |
64 | tree binfo = get_binfo (basetype, type, 0); | |
65 | ||
66 | exp = convert_pointer_to_real (binfo, exp); | |
67 | return exp; | |
68 | } | |
69 | ||
70 | /* Given the expression EXP of type `class *', return the head of the | |
71 | object pointed to by EXP with type cv void*, if the class has any | |
72 | virtual functions (TYPE_VIRTUAL_P), else just return the | |
73 | expression. */ | |
5566b478 | 74 | static tree |
84a43794 MS |
75 | build_headof (exp) |
76 | tree exp; | |
77 | { | |
78 | tree type = TREE_TYPE (exp); | |
6b5fbb55 | 79 | tree aref; |
84a43794 MS |
80 | tree vptr, offset; |
81 | ||
82 | if (TREE_CODE (type) != POINTER_TYPE) | |
83 | { | |
84 | error ("`headof' applied to non-pointer type"); | |
85 | return error_mark_node; | |
86 | } | |
87 | type = TREE_TYPE (type); | |
88 | ||
6b5fbb55 | 89 | if (!TYPE_VIRTUAL_P (type)) |
84a43794 MS |
90 | return exp; |
91 | ||
6b5fbb55 MS |
92 | /* If we don't have rtti stuff, get to a sub-object that does. */ |
93 | if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp)))) | |
94 | exp = build_headof_sub (exp); | |
95 | ||
96 | /* We use this a couple of times below, protect it. */ | |
97 | exp = save_expr (exp); | |
98 | ||
99 | aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node); | |
84a43794 MS |
100 | |
101 | if (flag_vtable_thunks) | |
6b5fbb55 | 102 | offset = aref; |
84a43794 | 103 | else |
6b5fbb55 | 104 | offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0); |
84a43794 MS |
105 | |
106 | type = build_type_variant (ptr_type_node, TREE_READONLY (exp), | |
107 | TREE_THIS_VOLATILE (exp)); | |
108 | return build (PLUS_EXPR, type, exp, | |
109 | convert (ptrdiff_type_node, offset)); | |
110 | } | |
111 | \f | |
112 | /* Return the type_info node associated with the expression EXP. If EXP is | |
113 | a reference to a polymorphic class, return the dynamic type; otherwise | |
114 | return the static type of the expression. */ | |
115 | tree | |
116 | build_typeid (exp) | |
117 | tree exp; | |
118 | { | |
119 | tree type; | |
120 | ||
84a43794 MS |
121 | if (exp == error_mark_node) |
122 | return error_mark_node; | |
123 | ||
124 | type = TREE_TYPE (exp); | |
125 | ||
126 | /* Strip top-level cv-qualifiers. */ | |
127 | type = TYPE_MAIN_VARIANT (type); | |
128 | ||
129 | /* if b is an instance of B, typeid(b) == typeid(B). Do this before | |
130 | reference trickiness. */ | |
131 | if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE) | |
132 | return get_typeid (type); | |
133 | ||
134 | /* peel back references, so they match. */ | |
135 | if (TREE_CODE (type) == REFERENCE_TYPE) | |
136 | type = TREE_TYPE (type); | |
137 | ||
138 | /* Peel off cv qualifiers. */ | |
139 | type = TYPE_MAIN_VARIANT (type); | |
140 | ||
141 | /* Apply trivial conversion T -> T& for dereferenced ptrs. */ | |
142 | if (TREE_CODE (type) == RECORD_TYPE) | |
143 | type = build_reference_type (type); | |
144 | ||
145 | /* If exp is a reference to polymorphic type, get the real type_info. */ | |
146 | if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type))) | |
147 | { | |
148 | /* build reference to type_info from vtable. */ | |
149 | tree t; | |
150 | ||
6b5fbb55 MS |
151 | if (! flag_rtti) |
152 | warning ("taking dynamic typeid of object without -frtti"); | |
153 | ||
154 | /* If we don't have rtti stuff, get to a sub-object that does. */ | |
155 | if (!CLASSTYPE_VFIELDS (TREE_TYPE (type))) | |
156 | { | |
157 | exp = build_unary_op (ADDR_EXPR, exp, 0); | |
158 | exp = build_headof_sub (exp); | |
159 | exp = build_indirect_ref (exp, NULL_PTR); | |
160 | } | |
161 | ||
84a43794 | 162 | if (flag_vtable_thunks) |
6b5fbb55 | 163 | t = build_vfn_ref ((tree *) 0, exp, integer_one_node); |
84a43794 | 164 | else |
6b5fbb55 MS |
165 | t = build_vfn_ref ((tree *) 0, exp, integer_zero_node); |
166 | TREE_TYPE (t) = build_pointer_type (tinfo_fn_type); | |
84a43794 | 167 | |
6b5fbb55 MS |
168 | t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type), t, NULL_TREE, 0); |
169 | TREE_SIDE_EFFECTS (t) = 1; | |
170 | return convert_from_reference (t); | |
84a43794 MS |
171 | } |
172 | ||
173 | /* otherwise return the type_info for the static type of the expr. */ | |
174 | return get_typeid (type); | |
175 | } | |
176 | ||
6b5fbb55 MS |
177 | tree |
178 | get_tinfo_var (type) | |
179 | tree type; | |
180 | { | |
181 | tree tname = build_overload_with_type (get_identifier ("__ti"), type); | |
182 | tree tdecl, arrtype; | |
183 | int size; | |
184 | ||
185 | if (IDENTIFIER_GLOBAL_VALUE (tname)) | |
186 | return IDENTIFIER_GLOBAL_VALUE (tname); | |
187 | ||
188 | /* Figure out how much space we need to allocate for the type_info object. | |
189 | If our struct layout or the type_info classes are changed, this will | |
190 | need to be modified. */ | |
191 | if (TYPE_VOLATILE (type) || TYPE_READONLY (type)) | |
192 | size = 4 * POINTER_SIZE; | |
193 | else if (TREE_CODE (type) == POINTER_TYPE | |
194 | && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE | |
195 | || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)) | |
196 | size = 3 * POINTER_SIZE; | |
197 | else if (IS_AGGR_TYPE (type)) | |
198 | { | |
199 | if (CLASSTYPE_N_BASECLASSES (type) == 0) | |
200 | size = 2 * POINTER_SIZE; | |
201 | else if (! TYPE_USES_COMPLEX_INHERITANCE (type) | |
202 | && (TREE_VIA_PUBLIC | |
203 | (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0)))) | |
204 | size = 3 * POINTER_SIZE; | |
205 | else | |
206 | size = 4 * POINTER_SIZE; | |
207 | } | |
208 | else | |
209 | size = 2 * POINTER_SIZE; | |
210 | ||
211 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
212 | ||
213 | /* The type for a character array of the appropriate size. */ | |
214 | arrtype = build_cplus_array_type | |
215 | (unsigned_char_type_node, | |
216 | build_index_type (size_int (size / BITS_PER_UNIT - 1))); | |
217 | ||
218 | tdecl = build_decl (VAR_DECL, tname, arrtype); | |
219 | TREE_PUBLIC (tdecl) = 1; | |
220 | DECL_EXTERNAL (tdecl) = 1; | |
221 | DECL_ARTIFICIAL (tdecl) = 1; | |
222 | pushdecl_top_level (tdecl); | |
223 | cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); | |
224 | ||
225 | pop_obstacks (); | |
226 | ||
227 | return tdecl; | |
228 | } | |
229 | ||
230 | tree | |
231 | get_tinfo_fn (type) | |
232 | tree type; | |
233 | { | |
234 | tree name = build_overload_with_type (tinfo_fn_id, type); | |
235 | tree d; | |
236 | ||
237 | if (IDENTIFIER_GLOBAL_VALUE (name)) | |
238 | return IDENTIFIER_GLOBAL_VALUE (name); | |
239 | ||
240 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
241 | ||
242 | d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type); | |
243 | DECL_EXTERNAL (d) = 1; | |
244 | TREE_PUBLIC (d) = 1; | |
245 | DECL_ARTIFICIAL (d) = 1; | |
246 | DECL_NOT_REALLY_EXTERN (d) = 1; | |
247 | DECL_MUTABLE_P (d) = 1; | |
248 | TREE_TYPE (name) = type; | |
249 | pushdecl_top_level (d); | |
250 | make_function_rtl (d); | |
251 | mark_inline_for_output (d); | |
252 | if (at_eof) | |
253 | import_export_decl (d); | |
254 | ||
255 | pop_obstacks (); | |
256 | ||
257 | return d; | |
258 | } | |
259 | ||
260 | tree | |
261 | get_typeid_1 (type) | |
262 | tree type; | |
263 | { | |
264 | tree t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type), | |
265 | default_conversion (get_tinfo_fn (type)), NULL_TREE, 0); | |
266 | TREE_SIDE_EFFECTS (t) = 1; | |
267 | return convert_from_reference (t); | |
268 | } | |
269 | ||
84a43794 MS |
270 | /* Return the type_info object for TYPE, creating it if necessary. */ |
271 | tree | |
272 | get_typeid (type) | |
273 | tree type; | |
274 | { | |
6b5fbb55 | 275 | tree t; |
84a43794 MS |
276 | |
277 | if (type == error_mark_node) | |
278 | return error_mark_node; | |
279 | ||
6b5fbb55 MS |
280 | /* If the type of the type-id is a reference type, the result of the |
281 | typeid expression refers to a type_info object representing the | |
282 | referenced type. */ | |
84a43794 MS |
283 | if (TREE_CODE (type) == REFERENCE_TYPE) |
284 | type = TREE_TYPE (type); | |
285 | ||
6b5fbb55 MS |
286 | /* The top-level cv-qualifiers of the lvalue expression or the type-id |
287 | that is the operand of typeid are always ignored. */ | |
288 | type = TYPE_MAIN_VARIANT (type); | |
84a43794 | 289 | |
6b5fbb55 | 290 | return get_typeid_1 (type); |
84a43794 MS |
291 | } |
292 | ||
293 | /* Get a bad_cast node for the program to throw... | |
294 | ||
6b5fbb55 MS |
295 | See libstdc++/exception.cc for __throw_bad_cast */ |
296 | ||
5566b478 | 297 | static tree |
6b5fbb55 | 298 | throw_bad_cast () |
84a43794 | 299 | { |
6b5fbb55 MS |
300 | tree d = get_identifier ("__throw_bad_cast"); |
301 | tree type; | |
302 | ||
303 | if (IDENTIFIER_GLOBAL_VALUE (d)) | |
304 | return IDENTIFIER_GLOBAL_VALUE (d); | |
305 | ||
306 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
307 | ||
308 | type = build_function_type (void_type_node, void_list_node); | |
309 | d = build_lang_decl (FUNCTION_DECL, d, type); | |
310 | DECL_EXTERNAL (d) = 1; | |
311 | TREE_PUBLIC (d) = 1; | |
312 | DECL_ARTIFICIAL (d) = 1; | |
313 | pushdecl_top_level (d); | |
314 | make_function_rtl (d); | |
315 | ||
316 | pop_obstacks (); | |
317 | ||
318 | d = build (CALL_EXPR, void_type_node, default_conversion (d), NULL_TREE, 0); | |
319 | TREE_SIDE_EFFECTS (d) = 1; | |
320 | return d; | |
84a43794 MS |
321 | } |
322 | ||
323 | /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working | |
324 | paper. */ | |
6b5fbb55 | 325 | |
84a43794 MS |
326 | tree |
327 | build_dynamic_cast (type, expr) | |
328 | tree type, expr; | |
329 | { | |
330 | enum tree_code tc = TREE_CODE (type); | |
331 | tree exprtype = TREE_TYPE (expr); | |
332 | enum tree_code ec = TREE_CODE (exprtype); | |
6b5fbb55 | 333 | tree dcast_fn; |
84a43794 MS |
334 | |
335 | if (type == error_mark_node || expr == error_mark_node) | |
336 | return error_mark_node; | |
337 | ||
338 | switch (tc) | |
339 | { | |
340 | case POINTER_TYPE: | |
341 | if (ec == REFERENCE_TYPE) | |
342 | { | |
343 | expr = convert_from_reference (expr); | |
344 | exprtype = TREE_TYPE (expr); | |
345 | ec = TREE_CODE (exprtype); | |
346 | } | |
347 | if (ec != POINTER_TYPE) | |
348 | goto fail; | |
349 | if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) | |
350 | goto fail; | |
cdf5b885 | 351 | if (TYPE_SIZE (TREE_TYPE (exprtype)) == NULL_TREE) |
84a43794 MS |
352 | goto fail; |
353 | if (TREE_READONLY (TREE_TYPE (exprtype)) && | |
354 | ! TYPE_READONLY (TREE_TYPE (type))) | |
355 | goto fail; | |
356 | if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) | |
357 | break; | |
358 | /* else fall through */ | |
359 | case REFERENCE_TYPE: | |
cdf5b885 MS |
360 | if (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE) |
361 | goto fail; | |
362 | if (TYPE_SIZE (TREE_TYPE (type)) == NULL_TREE) | |
363 | goto fail; | |
364 | break; | |
84a43794 MS |
365 | /* else fall through */ |
366 | default: | |
367 | goto fail; | |
368 | } | |
369 | ||
370 | /* Apply trivial conversion T -> T& for dereferenced ptrs. */ | |
371 | if (ec == RECORD_TYPE) | |
372 | { | |
373 | exprtype = build_type_variant (exprtype, TREE_READONLY (expr), | |
374 | TREE_THIS_VOLATILE (expr)); | |
375 | exprtype = build_reference_type (exprtype); | |
376 | expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT, | |
377 | LOOKUP_NORMAL, NULL_TREE); | |
378 | ec = REFERENCE_TYPE; | |
379 | } | |
380 | ||
381 | if (tc == REFERENCE_TYPE) | |
382 | { | |
383 | if (ec != REFERENCE_TYPE) | |
384 | goto fail; | |
385 | if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) | |
386 | goto fail; | |
cdf5b885 | 387 | if (TYPE_SIZE (TREE_TYPE (exprtype)) == NULL_TREE) |
84a43794 MS |
388 | goto fail; |
389 | if (TREE_READONLY (TREE_TYPE (exprtype)) && | |
390 | ! TYPE_READONLY (TREE_TYPE (type))) | |
391 | goto fail; | |
392 | } | |
393 | ||
394 | /* If *type is an unambiguous accessible base class of *exprtype, | |
395 | convert statically. */ | |
396 | { | |
397 | int distance; | |
398 | tree path; | |
399 | ||
400 | distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1, | |
401 | &path); | |
402 | if (distance >= 0) | |
403 | return build_vbase_path (PLUS_EXPR, type, expr, path, 0); | |
404 | } | |
405 | ||
406 | /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */ | |
407 | if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype))) | |
408 | { | |
409 | /* if TYPE is `void *', return pointer to complete object. */ | |
410 | if (tc == POINTER_TYPE | |
411 | && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) | |
412 | { | |
413 | /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */ | |
414 | if (TREE_CODE (expr) == ADDR_EXPR | |
415 | && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL | |
416 | && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE) | |
417 | return build1 (NOP_EXPR, type, expr); | |
418 | ||
6b5fbb55 MS |
419 | expr = build_headof (expr); |
420 | if (TREE_TYPE (expr) != type) | |
421 | expr = build1 (NOP_EXPR, type, expr); | |
422 | return expr; | |
84a43794 MS |
423 | } |
424 | else | |
425 | { | |
426 | tree retval; | |
6b5fbb55 | 427 | tree result, td1, td2, td3, elems, expr1, expr2; |
84a43794 MS |
428 | |
429 | /* If we got here, we can't convert statically. Therefore, | |
430 | dynamic_cast<D&>(b) (b an object) cannot succeed. */ | |
431 | if (ec == REFERENCE_TYPE) | |
432 | { | |
433 | if (TREE_CODE (expr) == VAR_DECL | |
434 | && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE) | |
435 | { | |
436 | cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", | |
437 | expr, type); | |
6b5fbb55 | 438 | return throw_bad_cast (); |
84a43794 MS |
439 | } |
440 | } | |
441 | /* Ditto for dynamic_cast<D*>(&b). */ | |
442 | else if (TREE_CODE (expr) == ADDR_EXPR) | |
443 | { | |
444 | tree op = TREE_OPERAND (expr, 0); | |
445 | if (TREE_CODE (op) == VAR_DECL | |
446 | && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE) | |
447 | { | |
448 | cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", | |
449 | expr, type); | |
450 | retval = build_int_2 (0, 0); | |
451 | TREE_TYPE (retval) = type; | |
452 | return retval; | |
453 | } | |
454 | } | |
455 | ||
6b5fbb55 MS |
456 | /* Since expr is used twice below, save it. */ |
457 | expr = save_expr (expr); | |
458 | ||
84a43794 MS |
459 | expr1 = expr; |
460 | if (tc == REFERENCE_TYPE) | |
461 | expr1 = build_unary_op (ADDR_EXPR, expr1, 0); | |
462 | ||
463 | /* Build run-time conversion. */ | |
6b5fbb55 | 464 | expr2 = build_headof (expr1); |
84a43794 MS |
465 | |
466 | if (ec == POINTER_TYPE) | |
467 | td1 = build_typeid (build_indirect_ref (expr, NULL_PTR)); | |
468 | else | |
469 | td1 = build_typeid (expr); | |
470 | ||
6b5fbb55 MS |
471 | td2 = get_typeid (TREE_TYPE (type)); |
472 | td3 = get_typeid (TREE_TYPE (exprtype)); | |
473 | ||
474 | elems = tree_cons | |
475 | (NULL_TREE, TREE_OPERAND (td1, 0), tree_cons | |
476 | (NULL_TREE, TREE_OPERAND (td2, 0), tree_cons | |
477 | (NULL_TREE, build_int_2 (1, 0), tree_cons | |
478 | (NULL_TREE, expr2, tree_cons | |
479 | (NULL_TREE, TREE_OPERAND (td3, 0), tree_cons | |
480 | (NULL_TREE, expr1, NULL_TREE)))))); | |
481 | ||
482 | dcast_fn = get_identifier ("__dynamic_cast"); | |
483 | if (IDENTIFIER_GLOBAL_VALUE (dcast_fn)) | |
484 | dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn); | |
485 | else | |
486 | { | |
487 | tree tmp; | |
488 | ||
489 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
490 | tmp = build_reference_type | |
491 | (build_type_variant (type_info_type_node, 1, 0)); | |
492 | tmp = tree_cons | |
493 | (NULL_TREE, tmp, tree_cons | |
494 | (NULL_TREE, tmp, tree_cons | |
495 | (NULL_TREE, integer_type_node, tree_cons | |
496 | (NULL_TREE, ptr_type_node, tree_cons | |
497 | (NULL_TREE, tmp, tree_cons | |
498 | (NULL_TREE, ptr_type_node, void_list_node)))))); | |
499 | tmp = build_function_type (ptr_type_node, tmp); | |
500 | dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp); | |
501 | DECL_EXTERNAL (dcast_fn) = 1; | |
502 | TREE_PUBLIC (dcast_fn) = 1; | |
503 | DECL_ARTIFICIAL (dcast_fn) = 1; | |
504 | pushdecl_top_level (dcast_fn); | |
505 | make_function_rtl (dcast_fn); | |
506 | pop_obstacks (); | |
507 | } | |
508 | ||
509 | result = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (dcast_fn)), | |
510 | decay_conversion (dcast_fn), elems, 0); | |
511 | TREE_SIDE_EFFECTS (result) = 1; | |
84a43794 MS |
512 | |
513 | if (tc == REFERENCE_TYPE) | |
514 | { | |
6b5fbb55 | 515 | expr1 = throw_bad_cast (); |
84a43794 MS |
516 | expr1 = build_compound_expr (tree_cons (NULL_TREE, expr1, |
517 | build_tree_list (NULL_TREE, convert (type, integer_zero_node)))); | |
518 | TREE_TYPE (expr1) = type; | |
519 | result = save_expr (result); | |
520 | return build (COND_EXPR, type, result, result, expr1); | |
521 | } | |
522 | ||
523 | /* Now back to the type we want from a void*. */ | |
524 | result = convert (type, result); | |
525 | return result; | |
526 | } | |
527 | } | |
528 | ||
529 | fail: | |
530 | cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'", | |
531 | expr, exprtype, type); | |
532 | return error_mark_node; | |
533 | } | |
534 | \f | |
535 | /* Build and initialize various sorts of descriptors. Every descriptor | |
536 | node has a name associated with it (the name created by mangling). | |
537 | For this reason, we use the identifier as our access to the __*_desc | |
538 | nodes, instead of sticking them directly in the types. Otherwise we | |
539 | would burden all built-in types (and pointer types) with slots that | |
540 | we don't necessarily want to use. | |
541 | ||
542 | For each descriptor we build, we build a variable that contains | |
543 | the descriptor's information. When we need this info at runtime, | |
544 | all we need is access to these variables. | |
545 | ||
546 | Note: these constructors always return the address of the descriptor | |
547 | info, since that is simplest for their mutual interaction. */ | |
548 | ||
6b5fbb55 | 549 | extern tree const_string_type_node; |
84a43794 | 550 | |
6b5fbb55 | 551 | /* Build an initializer for a __si_type_info node. */ |
84a43794 | 552 | |
6b5fbb55 MS |
553 | static void |
554 | expand_si_desc (tdecl, type) | |
84a43794 MS |
555 | tree tdecl; |
556 | tree type; | |
557 | { | |
6b5fbb55 MS |
558 | tree t, elems, fn; |
559 | char *name = build_overload_name (type, 1, 1); | |
560 | tree name_string = combine_strings (build_string (strlen (name), name)); | |
561 | ||
562 | type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0)); | |
563 | expand_expr_stmt (get_typeid_1 (type)); | |
564 | t = decay_conversion (get_tinfo_var (type)); | |
565 | elems = tree_cons | |
566 | (NULL_TREE, decay_conversion (tdecl), tree_cons | |
567 | (NULL_TREE, decay_conversion (name_string), tree_cons | |
568 | (NULL_TREE, t, NULL_TREE))); | |
569 | ||
570 | fn = get_identifier ("__rtti_si"); | |
571 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
572 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
84a43794 MS |
573 | else |
574 | { | |
6b5fbb55 MS |
575 | tree tmp; |
576 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
577 | tmp = tree_cons | |
578 | (NULL_TREE, ptr_type_node, tree_cons | |
579 | (NULL_TREE, const_string_type_node, tree_cons | |
580 | (NULL_TREE, build_pointer_type (type_info_type_node), | |
581 | void_list_node))); | |
582 | tmp = build_function_type (void_type_node, tmp); | |
583 | ||
584 | fn = build_lang_decl (FUNCTION_DECL, fn, tmp); | |
585 | DECL_EXTERNAL (fn) = 1; | |
586 | TREE_PUBLIC (fn) = 1; | |
587 | DECL_ARTIFICIAL (fn) = 1; | |
588 | pushdecl_top_level (fn); | |
589 | make_function_rtl (fn); | |
590 | pop_obstacks (); | |
84a43794 MS |
591 | } |
592 | ||
6b5fbb55 MS |
593 | fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), |
594 | decay_conversion (fn), elems, 0); | |
595 | TREE_SIDE_EFFECTS (fn) = 1; | |
596 | expand_expr_stmt (fn); | |
84a43794 MS |
597 | } |
598 | ||
599 | /* Build an initializer for a __class_type_info node. */ | |
6b5fbb55 MS |
600 | |
601 | static void | |
602 | expand_class_desc (tdecl, type) | |
84a43794 MS |
603 | tree tdecl; |
604 | tree type; | |
605 | { | |
6b5fbb55 | 606 | tree tname = TYPE_NESTED_NAME (type); |
84a43794 | 607 | tree name_string; |
6b5fbb55 MS |
608 | tree fn, tmp; |
609 | char *name; | |
84a43794 MS |
610 | |
611 | int i = CLASSTYPE_N_BASECLASSES (type); | |
84a43794 MS |
612 | int base_cnt = 0; |
613 | tree binfos = TYPE_BINFO_BASETYPES (type); | |
5566b478 MS |
614 | #if 0 |
615 | /* See code below that used these. */ | |
84a43794 | 616 | tree vb = CLASSTYPE_VBASECLASSES (type); |
5566b478 MS |
617 | int n_base = i; |
618 | #endif | |
84a43794 | 619 | tree base, elems, access, offset, isvir; |
6b5fbb55 MS |
620 | tree elt, elts = NULL_TREE; |
621 | static tree base_info_type_node; | |
84a43794 | 622 | |
6b5fbb55 | 623 | if (base_info_type_node == NULL_TREE) |
84a43794 | 624 | { |
6b5fbb55 MS |
625 | tree fields [4]; |
626 | ||
627 | /* A reasonably close approximation of __class_type_info::base_info */ | |
628 | ||
629 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
630 | base_info_type_node = make_lang_type (RECORD_TYPE); | |
631 | ||
632 | /* Actually const __user_type_info * */ | |
633 | fields [0] = build_lang_field_decl | |
634 | (FIELD_DECL, NULL_TREE, | |
635 | build_pointer_type (build_type_variant (type_info_type_node, 1, 0))); | |
636 | fields [1] = build_lang_field_decl | |
637 | (FIELD_DECL, NULL_TREE, sizetype); | |
638 | DECL_BIT_FIELD (fields[1]) = 1; | |
639 | DECL_FIELD_SIZE (fields[1]) = 29; | |
640 | ||
641 | fields [2] = build_lang_field_decl | |
642 | (FIELD_DECL, NULL_TREE, boolean_type_node); | |
643 | DECL_BIT_FIELD (fields[2]) = 1; | |
644 | DECL_FIELD_SIZE (fields[2]) = 1; | |
645 | ||
646 | /* Actually enum access */ | |
647 | fields [3] = build_lang_field_decl | |
648 | (FIELD_DECL, NULL_TREE, integer_type_node); | |
649 | DECL_BIT_FIELD (fields[3]) = 1; | |
650 | DECL_FIELD_SIZE (fields[3]) = 2; | |
651 | ||
652 | finish_builtin_type (base_info_type_node, "__base_info", fields, | |
653 | 3, ptr_type_node); | |
654 | pop_obstacks (); | |
84a43794 MS |
655 | } |
656 | ||
84a43794 MS |
657 | while (--i >= 0) |
658 | { | |
659 | tree binfo = TREE_VEC_ELT (binfos, i); | |
660 | ||
6b5fbb55 MS |
661 | expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo))); |
662 | base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo))); | |
663 | ||
84a43794 MS |
664 | if (TREE_VIA_VIRTUAL (binfo)) |
665 | { | |
666 | tree t = BINFO_TYPE (binfo); | |
667 | char *name; | |
668 | tree field; | |
84a43794 MS |
669 | |
670 | name = (char *) alloca (TYPE_NAME_LENGTH (t)+sizeof (VBASE_NAME)+1); | |
671 | sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (t)); | |
672 | field = lookup_field (type, get_identifier (name), 0, 0); | |
673 | offset = size_binop (FLOOR_DIV_EXPR, | |
674 | DECL_FIELD_BITPOS (field), size_int (BITS_PER_UNIT)); | |
675 | } | |
676 | else | |
677 | offset = BINFO_OFFSET (binfo); | |
678 | ||
679 | if (TREE_VIA_PUBLIC (binfo)) | |
6b5fbb55 | 680 | access = access_public_node; |
84a43794 | 681 | else if (TREE_VIA_PROTECTED (binfo)) |
6b5fbb55 | 682 | access = access_protected_node; |
84a43794 | 683 | else |
6b5fbb55 | 684 | access = access_private_node; |
84a43794 | 685 | if (TREE_VIA_VIRTUAL (binfo)) |
6b5fbb55 | 686 | isvir = boolean_true_node; |
84a43794 | 687 | else |
6b5fbb55 MS |
688 | isvir = boolean_false_node; |
689 | ||
690 | elt = build | |
691 | (CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons | |
692 | (NULL_TREE, base, tree_cons | |
693 | (NULL_TREE, offset, tree_cons | |
694 | (NULL_TREE, isvir, tree_cons | |
695 | (NULL_TREE, access, NULL_TREE))))); | |
696 | TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1; | |
697 | elts = tree_cons (NULL_TREE, elt, elts); | |
84a43794 MS |
698 | base_cnt++; |
699 | } | |
700 | #if 0 | |
701 | i = n_base; | |
702 | while (vb) | |
703 | { | |
704 | tree b; | |
6b5fbb55 | 705 | access = access_public_node; |
84a43794 MS |
706 | while (--i >= 0) |
707 | { | |
708 | b = TREE_VEC_ELT (binfos, i); | |
709 | if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b)) | |
710 | { | |
711 | if (TREE_VIA_PUBLIC (b)) | |
6b5fbb55 | 712 | access = access_public_node; |
84a43794 | 713 | else if (TREE_VIA_PROTECTED (b)) |
6b5fbb55 | 714 | access = access_protected_node; |
84a43794 | 715 | else |
6b5fbb55 | 716 | access = access_private_node; |
84a43794 MS |
717 | break; |
718 | } | |
719 | } | |
720 | base = build_t_desc (BINFO_TYPE (vb), 1); | |
721 | offset = BINFO_OFFSET (vb); | |
722 | isvir = build_int_2 (1, 0); | |
723 | ||
724 | base_list = tree_cons (NULL_TREE, base, base_list); | |
725 | isvir_list = tree_cons (NULL_TREE, isvir, isvir_list); | |
726 | acc_list = tree_cons (NULL_TREE, access, acc_list); | |
727 | off_list = tree_cons (NULL_TREE, offset, off_list); | |
728 | ||
729 | base_cnt++; | |
730 | vb = TREE_CHAIN (vb); | |
731 | } | |
732 | #endif | |
84a43794 | 733 | |
6b5fbb55 MS |
734 | name = build_overload_name (type, 1, 1); |
735 | name_string = combine_strings (build_string (strlen (name), name)); | |
84a43794 | 736 | |
6b5fbb55 MS |
737 | { |
738 | tree arrtype = build_array_type (base_info_type_node, NULL_TREE); | |
739 | elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts); | |
740 | TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts) = | |
741 | TREE_STATIC (elts) = 1; | |
742 | complete_array_type (arrtype, elts, 1); | |
743 | } | |
84a43794 | 744 | |
6b5fbb55 MS |
745 | elems = tree_cons |
746 | (NULL_TREE, decay_conversion (tdecl), tree_cons | |
747 | (NULL_TREE, decay_conversion (name_string), tree_cons | |
748 | (NULL_TREE, decay_conversion (elts), tree_cons | |
749 | (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE)))); | |
84a43794 | 750 | |
6b5fbb55 MS |
751 | fn = get_identifier ("__rtti_class"); |
752 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
753 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
84a43794 MS |
754 | else |
755 | { | |
6b5fbb55 MS |
756 | push_obstacks (&permanent_obstack, &permanent_obstack); |
757 | tmp = tree_cons | |
758 | (NULL_TREE, ptr_type_node, tree_cons | |
759 | (NULL_TREE, const_string_type_node, tree_cons | |
760 | (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons | |
761 | (NULL_TREE, sizetype, void_list_node)))); | |
762 | tmp = build_function_type (void_type_node, tmp); | |
763 | ||
764 | fn = build_lang_decl (FUNCTION_DECL, fn, tmp); | |
765 | DECL_EXTERNAL (fn) = 1; | |
766 | TREE_PUBLIC (fn) = 1; | |
767 | DECL_ARTIFICIAL (fn) = 1; | |
768 | pushdecl_top_level (fn); | |
769 | make_function_rtl (fn); | |
770 | pop_obstacks (); | |
84a43794 | 771 | } |
84a43794 | 772 | |
6b5fbb55 MS |
773 | fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), |
774 | decay_conversion (fn), elems, 0); | |
775 | TREE_SIDE_EFFECTS (fn) = 1; | |
776 | expand_expr_stmt (fn); | |
84a43794 MS |
777 | } |
778 | ||
6b5fbb55 MS |
779 | /* Build an initializer for a __pointer_type_info node. */ |
780 | static void | |
781 | expand_ptr_desc (tdecl, type) | |
84a43794 MS |
782 | tree tdecl; |
783 | tree type; | |
784 | { | |
6b5fbb55 MS |
785 | tree t, elems, fn; |
786 | char *name = build_overload_name (type, 1, 1); | |
787 | tree name_string = combine_strings (build_string (strlen (name), name)); | |
788 | ||
789 | type = TREE_TYPE (type); | |
790 | expand_expr_stmt (get_typeid_1 (type)); | |
791 | t = decay_conversion (get_tinfo_var (type)); | |
792 | elems = tree_cons | |
793 | (NULL_TREE, decay_conversion (tdecl), tree_cons | |
794 | (NULL_TREE, decay_conversion (name_string), tree_cons | |
795 | (NULL_TREE, t, NULL_TREE))); | |
796 | ||
797 | fn = get_identifier ("__rtti_ptr"); | |
798 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
799 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
800 | else | |
801 | { | |
802 | tree tmp; | |
803 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
804 | tmp = tree_cons | |
805 | (NULL_TREE, ptr_type_node, tree_cons | |
806 | (NULL_TREE, const_string_type_node, tree_cons | |
807 | (NULL_TREE, build_pointer_type (type_info_type_node), | |
808 | void_list_node))); | |
809 | tmp = build_function_type (void_type_node, tmp); | |
810 | ||
811 | fn = build_lang_decl (FUNCTION_DECL, fn, tmp); | |
812 | DECL_EXTERNAL (fn) = 1; | |
813 | TREE_PUBLIC (fn) = 1; | |
814 | DECL_ARTIFICIAL (fn) = 1; | |
815 | pushdecl_top_level (fn); | |
816 | make_function_rtl (fn); | |
817 | pop_obstacks (); | |
818 | } | |
819 | ||
820 | fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), | |
821 | decay_conversion (fn), elems, 0); | |
822 | TREE_SIDE_EFFECTS (fn) = 1; | |
823 | expand_expr_stmt (fn); | |
84a43794 MS |
824 | } |
825 | ||
6b5fbb55 | 826 | /* Build an initializer for a __attr_type_info node. */ |
84a43794 MS |
827 | |
828 | static void | |
6b5fbb55 MS |
829 | expand_attr_desc (tdecl, type) |
830 | tree tdecl; | |
84a43794 MS |
831 | tree type; |
832 | { | |
6b5fbb55 MS |
833 | tree elems, t, fn; |
834 | char *name = build_overload_name (type, 1, 1); | |
835 | tree name_string = combine_strings (build_string (strlen (name), name)); | |
836 | tree attrval = build_int_2 | |
837 | (TYPE_READONLY (type) | TYPE_VOLATILE (type) * 2, 0); | |
838 | ||
839 | expand_expr_stmt (get_typeid_1 (TYPE_MAIN_VARIANT (type))); | |
840 | t = decay_conversion (get_tinfo_var (TYPE_MAIN_VARIANT (type))); | |
841 | elems = tree_cons | |
842 | (NULL_TREE, decay_conversion (tdecl), tree_cons | |
843 | (NULL_TREE, decay_conversion (name_string), tree_cons | |
844 | (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE)))); | |
845 | ||
846 | fn = get_identifier ("__rtti_attr"); | |
847 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
848 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
849 | else | |
850 | { | |
851 | tree tmp; | |
852 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
853 | tmp = tree_cons | |
854 | (NULL_TREE, ptr_type_node, tree_cons | |
855 | (NULL_TREE, const_string_type_node, tree_cons | |
856 | (NULL_TREE, integer_type_node, tree_cons | |
857 | (NULL_TREE, build_pointer_type (type_info_type_node), | |
858 | void_list_node)))); | |
859 | tmp = build_function_type (void_type_node, tmp); | |
860 | ||
861 | fn = build_lang_decl (FUNCTION_DECL, fn, tmp); | |
862 | DECL_EXTERNAL (fn) = 1; | |
863 | TREE_PUBLIC (fn) = 1; | |
864 | DECL_ARTIFICIAL (fn) = 1; | |
865 | pushdecl_top_level (fn); | |
866 | make_function_rtl (fn); | |
867 | pop_obstacks (); | |
868 | } | |
84a43794 | 869 | |
6b5fbb55 MS |
870 | fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), |
871 | decay_conversion (fn), elems, 0); | |
872 | TREE_SIDE_EFFECTS (fn) = 1; | |
873 | expand_expr_stmt (fn); | |
84a43794 MS |
874 | } |
875 | ||
6b5fbb55 | 876 | /* Build an initializer for a type_info node that just has a name. */ |
84a43794 | 877 | |
6b5fbb55 MS |
878 | static void |
879 | expand_generic_desc (tdecl, type, fnname) | |
880 | tree tdecl; | |
84a43794 | 881 | tree type; |
6b5fbb55 | 882 | char *fnname; |
84a43794 | 883 | { |
6b5fbb55 MS |
884 | char *name = build_overload_name (type, 1, 1); |
885 | tree name_string = combine_strings (build_string (strlen (name), name)); | |
886 | tree elems = tree_cons | |
887 | (NULL_TREE, decay_conversion (tdecl), tree_cons | |
888 | (NULL_TREE, decay_conversion (name_string), NULL_TREE)); | |
889 | ||
890 | tree fn = get_identifier (fnname); | |
891 | if (IDENTIFIER_GLOBAL_VALUE (fn)) | |
892 | fn = IDENTIFIER_GLOBAL_VALUE (fn); | |
893 | else | |
84a43794 | 894 | { |
6b5fbb55 MS |
895 | tree tmp; |
896 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
897 | tmp = tree_cons | |
898 | (NULL_TREE, ptr_type_node, tree_cons | |
899 | (NULL_TREE, const_string_type_node, void_list_node)); | |
900 | tmp = build_function_type (void_type_node, tmp); | |
901 | ||
902 | fn = build_lang_decl (FUNCTION_DECL, fn, tmp); | |
903 | DECL_EXTERNAL (fn) = 1; | |
904 | TREE_PUBLIC (fn) = 1; | |
905 | DECL_ARTIFICIAL (fn) = 1; | |
906 | pushdecl_top_level (fn); | |
907 | make_function_rtl (fn); | |
908 | pop_obstacks (); | |
84a43794 | 909 | } |
84a43794 | 910 | |
6b5fbb55 MS |
911 | fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), |
912 | decay_conversion (fn), elems, 0); | |
913 | TREE_SIDE_EFFECTS (fn) = 1; | |
914 | expand_expr_stmt (fn); | |
915 | } | |
84a43794 | 916 | |
6b5fbb55 MS |
917 | /* Generate the code for a type_info initialization function. |
918 | Note that we take advantage of the passage | |
84a43794 | 919 | |
6b5fbb55 MS |
920 | 5.2.7 Type identification [expr.typeid] |
921 | ||
922 | Whether or not the destructor is called for the type_info object at the | |
923 | end of the program is unspecified. | |
84a43794 | 924 | |
6b5fbb55 MS |
925 | and don't bother to arrange for these objects to be destroyed. It |
926 | doesn't matter, anyway, since the destructors don't do anything. | |
927 | ||
928 | This must only be called from toplevel (i.e. from finish_file)! */ | |
84a43794 | 929 | |
6b5fbb55 MS |
930 | void |
931 | synthesize_tinfo_fn (fndecl) | |
932 | tree fndecl; | |
933 | { | |
934 | tree type = TREE_TYPE (DECL_NAME (fndecl)); | |
935 | tree tmp, addr; | |
84a43794 | 936 | |
6b5fbb55 MS |
937 | tree tdecl = get_tinfo_var (type); |
938 | DECL_EXTERNAL (tdecl) = 0; | |
939 | TREE_STATIC (tdecl) = 1; | |
940 | DECL_COMMON (tdecl) = 1; | |
941 | TREE_USED (tdecl) = 1; | |
942 | DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node); | |
943 | cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); | |
944 | ||
945 | start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1); | |
946 | store_parm_decls (); | |
947 | clear_last_expr (); | |
948 | push_momentary (); | |
949 | ||
950 | /* If the first word of the array (the vtable) is non-zero, we've already | |
951 | initialized the object, so don't do it again. */ | |
952 | addr = decay_conversion (tdecl); | |
953 | tmp = convert (build_pointer_type (ptr_type_node), addr); | |
954 | tmp = build_indirect_ref (tmp, 0); | |
955 | tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node, 1); | |
956 | expand_start_cond (tmp, 0); | |
84a43794 MS |
957 | |
958 | if (TYPE_VOLATILE (type) || TYPE_READONLY (type)) | |
6b5fbb55 | 959 | expand_attr_desc (tdecl, type); |
84a43794 | 960 | else if (TREE_CODE (type) == ARRAY_TYPE) |
6b5fbb55 | 961 | expand_generic_desc (tdecl, type, "__rtti_array"); |
84a43794 MS |
962 | else if (TREE_CODE (type) == POINTER_TYPE) |
963 | { | |
964 | if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE) | |
6b5fbb55 MS |
965 | expand_generic_desc (tdecl, type, "__rtti_ptmd"); |
966 | else if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE) | |
967 | expand_generic_desc (tdecl, type, "__rtti_ptmf"); | |
84a43794 | 968 | else |
6b5fbb55 | 969 | expand_ptr_desc (tdecl, type); |
84a43794 | 970 | } |
6b5fbb55 MS |
971 | else if (TYPE_PTRMEMFUNC_P (type)) |
972 | expand_generic_desc (tdecl, type, "__rtti_ptmf"); | |
84a43794 MS |
973 | else if (IS_AGGR_TYPE (type)) |
974 | { | |
6b5fbb55 MS |
975 | if (CLASSTYPE_N_BASECLASSES (type) == 0) |
976 | expand_generic_desc (tdecl, type, "__rtti_user"); | |
977 | else if (! TYPE_USES_COMPLEX_INHERITANCE (type) | |
978 | && (TREE_VIA_PUBLIC | |
979 | (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0)))) | |
980 | expand_si_desc (tdecl, type); | |
84a43794 | 981 | else |
6b5fbb55 | 982 | expand_class_desc (tdecl, type); |
84a43794 | 983 | } |
6b5fbb55 MS |
984 | else if (TREE_CODE (type) == ENUMERAL_TYPE) |
985 | expand_generic_desc (tdecl, type, "__rtti_user"); | |
84a43794 | 986 | else if (TREE_CODE (type) == FUNCTION_TYPE) |
6b5fbb55 MS |
987 | expand_generic_desc (tdecl, type, "__rtti_func"); |
988 | else | |
989 | my_friendly_abort (252); | |
84a43794 | 990 | |
6b5fbb55 MS |
991 | expand_end_cond (); |
992 | ||
993 | /* OK, now return the type_info object. */ | |
994 | tmp = convert (build_pointer_type (type_info_type_node), addr); | |
995 | tmp = build_indirect_ref (tmp, 0); | |
996 | c_expand_return (tmp); | |
997 | finish_function (lineno, 0, 0); | |
84a43794 MS |
998 | } |
999 | ||
1000 | #if 0 | |
1001 | /* This is the old dossier type descriptor generation code, it's much | |
1002 | more extended than rtti. It's reserved for later use. */ | |
1003 | /* Build an initializer for a __t_desc node. So that we can take advantage | |
1004 | of recursion, we accept NULL for TYPE. | |
1005 | DEFINITION is greater than zero iff we must define the type descriptor | |
1006 | (as opposed to merely referencing it). 1 means treat according to | |
1007 | #pragma interface/#pragma implementation rules. 2 means define as | |
1008 | global and public, no matter what. */ | |
1009 | tree | |
1010 | build_t_desc (type, definition) | |
1011 | tree type; | |
1012 | int definition; | |
1013 | { | |
1014 | tree tdecl; | |
1015 | tree tname, name_string; | |
1016 | tree elems, fields; | |
1017 | tree parents, vbases, offsets, ivars, methods, target_type; | |
1018 | int method_count = 0, field_count = 0; | |
1019 | ||
1020 | if (type == NULL_TREE) | |
1021 | return NULL_TREE; | |
1022 | ||
1023 | tname = build_t_desc_overload (type); | |
1024 | if (IDENTIFIER_AS_DESC (tname) | |
1025 | && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))) | |
1026 | return IDENTIFIER_AS_DESC (tname); | |
1027 | ||
1028 | tdecl = lookup_name (tname, 0); | |
1029 | if (tdecl == NULL_TREE) | |
1030 | { | |
1031 | tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); | |
1032 | DECL_EXTERNAL (tdecl) = 1; | |
1033 | TREE_PUBLIC (tdecl) = 1; | |
1034 | tdecl = pushdecl_top_level (tdecl); | |
1035 | } | |
1036 | /* If we previously defined it, return the defined result. */ | |
1037 | else if (definition && DECL_INITIAL (tdecl)) | |
1038 | return IDENTIFIER_AS_DESC (tname); | |
1039 | ||
1040 | if (definition) | |
1041 | { | |
1042 | tree taggr = type; | |
1043 | /* Let T* and T& be written only when T is written (if T is an aggr). | |
1044 | We do this for const, but not for volatile, since volatile | |
1045 | is rare and const is not. */ | |
1046 | if (!TYPE_VOLATILE (taggr) | |
1047 | && (TREE_CODE (taggr) == POINTER_TYPE | |
1048 | || TREE_CODE (taggr) == REFERENCE_TYPE) | |
1049 | && IS_AGGR_TYPE (TREE_TYPE (taggr))) | |
1050 | taggr = TREE_TYPE (taggr); | |
1051 | ||
1052 | /* If we know that we don't need to write out this type's | |
1053 | vtable, then don't write out it's dossier. Somebody | |
1054 | else will take care of that. */ | |
1055 | if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) | |
1056 | { | |
1057 | if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr)) | |
1058 | { | |
1059 | TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr) | |
1060 | && CLASSTYPE_INTERFACE_KNOWN (taggr); | |
1061 | DECL_EXTERNAL (tdecl) = 0; | |
1062 | } | |
1063 | else | |
1064 | { | |
1065 | if (write_virtuals != 0) | |
1066 | TREE_PUBLIC (tdecl) = 1; | |
1067 | } | |
1068 | } | |
1069 | else | |
1070 | { | |
1071 | DECL_EXTERNAL (tdecl) = 0; | |
1072 | TREE_PUBLIC (tdecl) = (definition > 1); | |
1073 | } | |
1074 | } | |
1075 | SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); | |
1076 | ||
1077 | if (!definition || DECL_EXTERNAL (tdecl)) | |
1078 | { | |
1079 | /* That's it! */ | |
1080 | cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); | |
1081 | return IDENTIFIER_AS_DESC (tname); | |
1082 | } | |
1083 | ||
1084 | /* Show that we are defining the t_desc for this type. */ | |
1085 | DECL_INITIAL (tdecl) = error_mark_node; | |
1086 | ||
1087 | parents = build_tree_list (NULL_TREE, integer_zero_node); | |
1088 | vbases = build_tree_list (NULL_TREE, integer_zero_node); | |
1089 | offsets = build_tree_list (NULL_TREE, integer_zero_node); | |
1090 | methods = NULL_TREE; | |
1091 | ivars = NULL_TREE; | |
1092 | ||
1093 | if (TYPE_LANG_SPECIFIC (type)) | |
1094 | { | |
1095 | int i = CLASSTYPE_N_BASECLASSES (type); | |
1096 | tree method_vec = CLASSTYPE_METHOD_VEC (type); | |
1097 | tree *meth, *end; | |
1098 | tree binfos = TYPE_BINFO_BASETYPES (type); | |
1099 | tree vb = CLASSTYPE_VBASECLASSES (type); | |
1100 | ||
1101 | while (--i >= 0) | |
1102 | parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents); | |
1103 | ||
1104 | while (vb) | |
1105 | { | |
1106 | vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases); | |
1107 | offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets); | |
1108 | vb = TREE_CHAIN (vb); | |
1109 | } | |
1110 | ||
1111 | if (method_vec) | |
1112 | for (meth = TREE_VEC_END (method_vec), | |
1113 | end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; ) | |
1114 | if (*meth) | |
1115 | { | |
1116 | methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods); | |
1117 | method_count++; | |
1118 | } | |
1119 | } | |
1120 | ||
1121 | if (IS_AGGR_TYPE (type)) | |
1122 | { | |
1123 | for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) | |
1124 | if (TREE_CODE (fields) == FIELD_DECL | |
1125 | || TREE_CODE (fields) == VAR_DECL) | |
1126 | { | |
1127 | ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars); | |
1128 | field_count++; | |
1129 | } | |
1130 | ivars = nreverse (ivars); | |
1131 | } | |
1132 | ||
1133 | parents = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), parents, 0); | |
1134 | vbases = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), vbases, 0); | |
1135 | offsets = finish_table (NULL_TREE, integer_type_node, offsets, 0); | |
1136 | if (methods == NULL_TREE) | |
1137 | methods = null_pointer_node; | |
1138 | else | |
1139 | methods = build_unary_op (ADDR_EXPR, | |
1140 | finish_table (NULL_TREE, __m_desc_type_node, methods, 0), | |
1141 | 0); | |
1142 | if (ivars == NULL_TREE) | |
1143 | ivars = null_pointer_node; | |
1144 | else | |
1145 | ivars = build_unary_op (ADDR_EXPR, | |
1146 | finish_table (NULL_TREE, __i_desc_type_node, ivars, 0), | |
1147 | 0); | |
1148 | if (TREE_TYPE (type)) | |
1149 | target_type = build_t_desc (TREE_TYPE (type), definition); | |
1150 | else | |
1151 | target_type = integer_zero_node; | |
1152 | ||
1153 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); | |
1154 | ||
1155 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), | |
1156 | tree_cons (NULL_TREE, | |
1157 | TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node, | |
1158 | /* really should use bitfield initialization here. */ | |
1159 | tree_cons (NULL_TREE, integer_zero_node, | |
1160 | tree_cons (NULL_TREE, target_type, | |
1161 | tree_cons (NULL_TREE, build_int_2 (field_count, 2), | |
1162 | tree_cons (NULL_TREE, build_int_2 (method_count, 2), | |
1163 | tree_cons (NULL_TREE, ivars, | |
1164 | tree_cons (NULL_TREE, methods, | |
1165 | tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0), | |
1166 | tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0), | |
1167 | build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0)))))))))))); | |
1168 | return build_generic_desc (tdecl, elems); | |
1169 | } | |
1170 | ||
1171 | /* Build an initializer for a __i_desc node. */ | |
1172 | tree | |
1173 | build_i_desc (decl) | |
1174 | tree decl; | |
1175 | { | |
1176 | tree elems, name_string; | |
1177 | tree taggr; | |
1178 | ||
1179 | name_string = DECL_NAME (decl); | |
1180 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); | |
1181 | ||
1182 | /* Now decide whether this ivar should cause it's type to get | |
1183 | def'd or ref'd in this file. If the type we are looking at | |
1184 | has a proxy definition, we look at the proxy (i.e., a | |
1185 | `foo *' is equivalent to a `foo'). */ | |
1186 | taggr = TREE_TYPE (decl); | |
1187 | ||
1188 | if ((TREE_CODE (taggr) == POINTER_TYPE | |
1189 | || TREE_CODE (taggr) == REFERENCE_TYPE) | |
1190 | && TYPE_VOLATILE (taggr) == 0) | |
1191 | taggr = TREE_TYPE (taggr); | |
1192 | ||
1193 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), | |
1194 | tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl), | |
1195 | build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl), | |
1196 | ! IS_AGGR_TYPE (taggr))))); | |
1197 | taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems); | |
1198 | TREE_CONSTANT (taggr) = 1; | |
1199 | TREE_STATIC (taggr) = 1; | |
1200 | TREE_READONLY (taggr) = 1; | |
1201 | return taggr; | |
1202 | } | |
1203 | ||
1204 | /* Build an initializer for a __m_desc node. */ | |
1205 | tree | |
1206 | build_m_desc (decl) | |
1207 | tree decl; | |
1208 | { | |
1209 | tree taggr, elems, name_string; | |
1210 | tree parm_count, req_count, vindex, vcontext; | |
1211 | tree parms; | |
1212 | int p_count, r_count; | |
1213 | tree parm_types = NULL_TREE; | |
1214 | ||
1215 | for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0; | |
1216 | parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++) | |
1217 | { | |
1218 | taggr = TREE_VALUE (parms); | |
1219 | if ((TREE_CODE (taggr) == POINTER_TYPE | |
1220 | || TREE_CODE (taggr) == REFERENCE_TYPE) | |
1221 | && TYPE_VOLATILE (taggr) == 0) | |
1222 | taggr = TREE_TYPE (taggr); | |
1223 | ||
1224 | parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms), | |
1225 | ! IS_AGGR_TYPE (taggr)), | |
1226 | parm_types); | |
1227 | if (TREE_PURPOSE (parms) == NULL_TREE) | |
1228 | r_count++; | |
1229 | } | |
1230 | ||
1231 | parm_types = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), | |
1232 | nreverse (parm_types), 0); | |
1233 | parm_count = build_int_2 (p_count, 0); | |
1234 | req_count = build_int_2 (r_count, 0); | |
1235 | ||
1236 | if (DECL_VINDEX (decl)) | |
1237 | vindex = DECL_VINDEX (decl); | |
1238 | else | |
1239 | vindex = integer_zero_node; | |
1240 | if (DECL_CONTEXT (decl) | |
1241 | && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') | |
1242 | vcontext = build_t_desc (DECL_CONTEXT (decl), 0); | |
1243 | else | |
1244 | vcontext = integer_zero_node; | |
1245 | name_string = DECL_NAME (decl); | |
1246 | if (name_string == NULL) | |
1247 | name_string = DECL_ASSEMBLER_NAME (decl); | |
1248 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); | |
1249 | ||
1250 | /* Now decide whether the return type of this mvar | |
1251 | should cause it's type to get def'd or ref'd in this file. | |
1252 | If the type we are looking at has a proxy definition, | |
1253 | we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */ | |
1254 | taggr = TREE_TYPE (TREE_TYPE (decl)); | |
1255 | ||
1256 | if ((TREE_CODE (taggr) == POINTER_TYPE | |
1257 | || TREE_CODE (taggr) == REFERENCE_TYPE) | |
1258 | && TYPE_VOLATILE (taggr) == 0) | |
1259 | taggr = TREE_TYPE (taggr); | |
1260 | ||
1261 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), | |
1262 | tree_cons (NULL_TREE, vindex, | |
1263 | tree_cons (NULL_TREE, vcontext, | |
1264 | tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)), | |
1265 | ! IS_AGGR_TYPE (taggr)), | |
1266 | tree_cons (NULL_TREE, build_c_cast (build_pointer_type (default_function_type), build_unary_op (ADDR_EXPR, decl, 0), 0), | |
1267 | tree_cons (NULL_TREE, parm_count, | |
1268 | tree_cons (NULL_TREE, req_count, | |
1269 | build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0))))))))); | |
1270 | ||
1271 | taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems); | |
1272 | TREE_CONSTANT (taggr) = 1; | |
1273 | TREE_STATIC (taggr) = 1; | |
1274 | TREE_READONLY (taggr) = 1; | |
1275 | return taggr; | |
1276 | } | |
1277 | #endif /* dossier */ |