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