1 | /* Garbage collection primitives for GNU C++. |
---|
2 | Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
---|
3 | Contributed by Michael Tiemann (tiemann@cygnus.com) |
---|
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 | |
---|
36 | /* This is the function decl for the (pseudo-builtin) __gc_protect |
---|
37 | function. Args are (class *value, int index); Returns value. */ |
---|
38 | tree gc_protect_fndecl; |
---|
39 | |
---|
40 | /* This is the function decl for the (pseudo-builtin) __gc_unprotect |
---|
41 | function. Args are (int index); void return. */ |
---|
42 | tree gc_unprotect_fndecl; |
---|
43 | |
---|
44 | /* This is the function decl for the (pseudo-builtin) __gc_push |
---|
45 | function. Args are (int length); void return. */ |
---|
46 | tree gc_push_fndecl; |
---|
47 | |
---|
48 | /* This is the function decl for the (pseudo-builtin) __gc_pop |
---|
49 | function. Args are void; void return. */ |
---|
50 | tree gc_pop_fndecl; |
---|
51 | |
---|
52 | /* Special integers that are used to represent bits in gc-safe objects. */ |
---|
53 | tree gc_nonobject; |
---|
54 | tree gc_visible; |
---|
55 | tree gc_white; |
---|
56 | tree gc_offwhite; |
---|
57 | tree gc_grey; |
---|
58 | tree gc_black; |
---|
59 | |
---|
60 | /* in c-common.c */ |
---|
61 | extern tree combine_strings PROTO((tree)); |
---|
62 | |
---|
63 | /* Predicate that returns non-zero if TYPE needs some kind of |
---|
64 | entry for the GC. Returns zero otherwise. */ |
---|
65 | int |
---|
66 | type_needs_gc_entry (type) |
---|
67 | tree type; |
---|
68 | { |
---|
69 | tree ttype = type; |
---|
70 | |
---|
71 | if (! flag_gc || type == error_mark_node) |
---|
72 | return 0; |
---|
73 | |
---|
74 | /* Aggregate types need gc entries if any of their members |
---|
75 | need gc entries. */ |
---|
76 | if (IS_AGGR_TYPE (type)) |
---|
77 | { |
---|
78 | tree binfos; |
---|
79 | tree fields = TYPE_FIELDS (type); |
---|
80 | int i; |
---|
81 | |
---|
82 | /* We don't care about certain pointers. Pointers |
---|
83 | to virtual baseclasses are always up front. We also |
---|
84 | cull out virtual function table pointers because it's |
---|
85 | easy, and it simplifies the logic.*/ |
---|
86 | while (fields |
---|
87 | && (DECL_NAME (fields) == NULL_TREE |
---|
88 | || VFIELD_NAME_P (DECL_NAME (fields)) |
---|
89 | || VBASE_NAME_P (DECL_NAME (fields)) |
---|
90 | || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits"))) |
---|
91 | fields = TREE_CHAIN (fields); |
---|
92 | |
---|
93 | while (fields) |
---|
94 | { |
---|
95 | if (type_needs_gc_entry (TREE_TYPE (fields))) |
---|
96 | return 1; |
---|
97 | fields = TREE_CHAIN (fields); |
---|
98 | } |
---|
99 | |
---|
100 | binfos = TYPE_BINFO_BASETYPES (type); |
---|
101 | if (binfos) |
---|
102 | for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) |
---|
103 | if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i)))) |
---|
104 | return 1; |
---|
105 | |
---|
106 | return 0; |
---|
107 | } |
---|
108 | |
---|
109 | while (TREE_CODE (ttype) == ARRAY_TYPE |
---|
110 | && TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE) |
---|
111 | ttype = TREE_TYPE (ttype); |
---|
112 | if ((TREE_CODE (ttype) == POINTER_TYPE |
---|
113 | || TREE_CODE (ttype) == ARRAY_TYPE |
---|
114 | || TREE_CODE (ttype) == REFERENCE_TYPE) |
---|
115 | && IS_AGGR_TYPE (TREE_TYPE (ttype)) |
---|
116 | && CLASSTYPE_RTTI (TREE_TYPE (ttype))) |
---|
117 | return 1; |
---|
118 | |
---|
119 | return 0; |
---|
120 | } |
---|
121 | |
---|
122 | /* Predicate that returns non-zero iff FROM is safe from the GC. |
---|
123 | |
---|
124 | If TO is nonzero, it means we know that FROM is being stored |
---|
125 | in TO, which make make it safe. */ |
---|
126 | int |
---|
127 | value_safe_from_gc (to, from) |
---|
128 | tree to, from; |
---|
129 | { |
---|
130 | /* First, return non-zero for easy cases: parameters, |
---|
131 | static variables. */ |
---|
132 | if (TREE_CODE (from) == PARM_DECL |
---|
133 | || (TREE_CODE (from) == VAR_DECL |
---|
134 | && TREE_STATIC (from))) |
---|
135 | return 1; |
---|
136 | |
---|
137 | /* If something has its address taken, it cannot be |
---|
138 | in the heap, so it doesn't need to be protected. */ |
---|
139 | if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from)) |
---|
140 | return 1; |
---|
141 | |
---|
142 | /* If we are storing into a static variable, then what |
---|
143 | we store will be safe from the gc. */ |
---|
144 | if (to && TREE_CODE (to) == VAR_DECL |
---|
145 | && TREE_STATIC (to)) |
---|
146 | return 1; |
---|
147 | |
---|
148 | /* Now recurse on structure of FROM. */ |
---|
149 | switch (TREE_CODE (from)) |
---|
150 | { |
---|
151 | case COMPONENT_REF: |
---|
152 | /* These guys are special, and safe. */ |
---|
153 | if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL |
---|
154 | && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))) |
---|
155 | || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))))) |
---|
156 | return 1; |
---|
157 | /* fall through... */ |
---|
158 | case NOP_EXPR: |
---|
159 | case CONVERT_EXPR: |
---|
160 | case NON_LVALUE_EXPR: |
---|
161 | case WITH_CLEANUP_EXPR: |
---|
162 | case SAVE_EXPR: |
---|
163 | case PREDECREMENT_EXPR: |
---|
164 | case PREINCREMENT_EXPR: |
---|
165 | case POSTDECREMENT_EXPR: |
---|
166 | case POSTINCREMENT_EXPR: |
---|
167 | if (value_safe_from_gc (to, TREE_OPERAND (from, 0))) |
---|
168 | return 1; |
---|
169 | break; |
---|
170 | |
---|
171 | case VAR_DECL: |
---|
172 | case PARM_DECL: |
---|
173 | /* We can safely pass these things as parameters to functions. */ |
---|
174 | if (to == 0) |
---|
175 | return 1; |
---|
176 | |
---|
177 | case ARRAY_REF: |
---|
178 | case INDIRECT_REF: |
---|
179 | case RESULT_DECL: |
---|
180 | case OFFSET_REF: |
---|
181 | case CALL_EXPR: |
---|
182 | case METHOD_CALL_EXPR: |
---|
183 | break; |
---|
184 | |
---|
185 | case COMPOUND_EXPR: |
---|
186 | case TARGET_EXPR: |
---|
187 | if (value_safe_from_gc (to, TREE_OPERAND (from, 1))) |
---|
188 | return 1; |
---|
189 | break; |
---|
190 | |
---|
191 | case COND_EXPR: |
---|
192 | if (value_safe_from_gc (to, TREE_OPERAND (from, 1)) |
---|
193 | && value_safe_from_gc (to, TREE_OPERAND (from, 2))) |
---|
194 | return 1; |
---|
195 | break; |
---|
196 | |
---|
197 | case PLUS_EXPR: |
---|
198 | case MINUS_EXPR: |
---|
199 | if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0))) |
---|
200 | || value_safe_from_gc (to, TREE_OPERAND (from, 0))) |
---|
201 | && (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0 |
---|
202 | || value_safe_from_gc (to, TREE_OPERAND (from, 1)))) |
---|
203 | return 1; |
---|
204 | break; |
---|
205 | |
---|
206 | case RTL_EXPR: |
---|
207 | /* Every time we build an RTL_EXPR in the front-end, we must |
---|
208 | ensure that everything in it is safe from the garbage collector. |
---|
209 | ??? This has only been done for `build_new'. */ |
---|
210 | return 1; |
---|
211 | |
---|
212 | default: |
---|
213 | my_friendly_abort (41); |
---|
214 | } |
---|
215 | |
---|
216 | if (to == 0) |
---|
217 | return 0; |
---|
218 | |
---|
219 | /* FROM wasn't safe. But other properties of TO might make it safe. */ |
---|
220 | switch (TREE_CODE (to)) |
---|
221 | { |
---|
222 | case VAR_DECL: |
---|
223 | case PARM_DECL: |
---|
224 | /* We already culled out static VAR_DECLs above. */ |
---|
225 | return 0; |
---|
226 | |
---|
227 | case COMPONENT_REF: |
---|
228 | /* These guys are special, and safe. */ |
---|
229 | if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL |
---|
230 | && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))) |
---|
231 | || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))))) |
---|
232 | return 1; |
---|
233 | /* fall through... */ |
---|
234 | |
---|
235 | case NOP_EXPR: |
---|
236 | case NON_LVALUE_EXPR: |
---|
237 | case WITH_CLEANUP_EXPR: |
---|
238 | case SAVE_EXPR: |
---|
239 | case PREDECREMENT_EXPR: |
---|
240 | case PREINCREMENT_EXPR: |
---|
241 | case POSTDECREMENT_EXPR: |
---|
242 | case POSTINCREMENT_EXPR: |
---|
243 | return value_safe_from_gc (TREE_OPERAND (to, 0), from); |
---|
244 | |
---|
245 | case COMPOUND_EXPR: |
---|
246 | case TARGET_EXPR: |
---|
247 | return value_safe_from_gc (TREE_OPERAND (to, 1), from); |
---|
248 | |
---|
249 | case COND_EXPR: |
---|
250 | return (value_safe_from_gc (TREE_OPERAND (to, 1), from) |
---|
251 | && value_safe_from_gc (TREE_OPERAND (to, 2), from)); |
---|
252 | |
---|
253 | case INDIRECT_REF: |
---|
254 | case ARRAY_REF: |
---|
255 | /* This used to be 0, but our current restricted model |
---|
256 | allows this to be 1. We'll never get arrays this way. */ |
---|
257 | return 1; |
---|
258 | |
---|
259 | default: |
---|
260 | my_friendly_abort (42); |
---|
261 | } |
---|
262 | |
---|
263 | /* Catch-all case is that TO/FROM is not safe. */ |
---|
264 | return 0; |
---|
265 | } |
---|
266 | |
---|
267 | /* Function to build a static GC entry for DECL. TYPE is DECL's type. |
---|
268 | |
---|
269 | For objects of type `class *', this is just an entry in the |
---|
270 | static vector __PTR_LIST__. |
---|
271 | |
---|
272 | For objects of type `class[]', this requires building an entry |
---|
273 | in the static vector __ARR_LIST__. |
---|
274 | |
---|
275 | For aggregates, this records all fields of type `class *' |
---|
276 | and `class[]' in the respective lists above. */ |
---|
277 | void |
---|
278 | build_static_gc_entry (decl, type) |
---|
279 | tree decl; |
---|
280 | tree type; |
---|
281 | { |
---|
282 | /* Now, figure out what sort of entry to build. */ |
---|
283 | if (TREE_CODE (type) == POINTER_TYPE |
---|
284 | || TREE_CODE (type) == REFERENCE_TYPE) |
---|
285 | assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl))); |
---|
286 | else if (TREE_CODE (type) == RECORD_TYPE) |
---|
287 | { |
---|
288 | tree ref = get_temp_name (build_reference_type (type), 1); |
---|
289 | DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl); |
---|
290 | TREE_CONSTANT (DECL_INITIAL (ref)) = 1; |
---|
291 | cp_finish_decl (ref, DECL_INITIAL (ref), NULL_TREE, 0, 0); |
---|
292 | } |
---|
293 | else |
---|
294 | { |
---|
295 | /* Not yet implemented. |
---|
296 | |
---|
297 | Cons up a static variable that holds address and length info |
---|
298 | and add that to ___ARR_LIST__. */ |
---|
299 | my_friendly_abort (43); |
---|
300 | } |
---|
301 | } |
---|
302 | |
---|
303 | /* Protect FROM from the GC, assuming FROM is going to be |
---|
304 | stored into TO. We handle three cases for TO here: |
---|
305 | |
---|
306 | case 1: TO is a stack variable. |
---|
307 | case 2: TO is zero (which means it is a parameter). |
---|
308 | case 3: TO is a return value. */ |
---|
309 | |
---|
310 | tree |
---|
311 | protect_value_from_gc (to, from) |
---|
312 | tree to, from; |
---|
313 | { |
---|
314 | if (to == 0) |
---|
315 | { |
---|
316 | tree cleanup; |
---|
317 | |
---|
318 | to = get_temp_regvar (TREE_TYPE (from), from); |
---|
319 | |
---|
320 | /* Convert from integer to list form since we'll use it twice. */ |
---|
321 | DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); |
---|
322 | cleanup = build_function_call (gc_unprotect_fndecl, |
---|
323 | DECL_GC_OFFSET (to)); |
---|
324 | |
---|
325 | if (! cp_expand_decl_cleanup (to, cleanup)) |
---|
326 | { |
---|
327 | compiler_error ("cannot unprotect parameter in this scope"); |
---|
328 | return error_mark_node; |
---|
329 | } |
---|
330 | } |
---|
331 | |
---|
332 | /* Should never need to protect a value that's headed for static storage. */ |
---|
333 | if (TREE_STATIC (to)) |
---|
334 | my_friendly_abort (44); |
---|
335 | |
---|
336 | switch (TREE_CODE (to)) |
---|
337 | { |
---|
338 | case COMPONENT_REF: |
---|
339 | case INDIRECT_REF: |
---|
340 | return protect_value_from_gc (TREE_OPERAND (to, 0), from); |
---|
341 | |
---|
342 | case VAR_DECL: |
---|
343 | case PARM_DECL: |
---|
344 | { |
---|
345 | tree rval; |
---|
346 | if (DECL_GC_OFFSET (to) == NULL_TREE) |
---|
347 | { |
---|
348 | /* Because of a cast or a conversion, we might stick |
---|
349 | a value into a variable that would not normally |
---|
350 | have a GC entry. */ |
---|
351 | DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index); |
---|
352 | } |
---|
353 | |
---|
354 | if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST) |
---|
355 | { |
---|
356 | DECL_GC_OFFSET (to) |
---|
357 | = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); |
---|
358 | } |
---|
359 | |
---|
360 | current_function_obstack_usage = 1; |
---|
361 | rval = build_function_call (gc_protect_fndecl, |
---|
362 | tree_cons (NULL_TREE, from, |
---|
363 | DECL_GC_OFFSET (to))); |
---|
364 | TREE_TYPE (rval) = TREE_TYPE (from); |
---|
365 | return rval; |
---|
366 | } |
---|
367 | } |
---|
368 | |
---|
369 | /* If we fall through the switch, assume we lost. */ |
---|
370 | my_friendly_abort (45); |
---|
371 | /* NOTREACHED */ |
---|
372 | return NULL_TREE; |
---|
373 | } |
---|
374 | |
---|
375 | /* Given the expression EXP of type `class *', return the head |
---|
376 | of the object pointed to by EXP. */ |
---|
377 | tree |
---|
378 | build_headof (exp) |
---|
379 | tree exp; |
---|
380 | { |
---|
381 | tree type = TREE_TYPE (exp); |
---|
382 | tree vptr, offset; |
---|
383 | |
---|
384 | if (TREE_CODE (type) != POINTER_TYPE) |
---|
385 | { |
---|
386 | error ("`headof' applied to non-pointer type"); |
---|
387 | return error_mark_node; |
---|
388 | } |
---|
389 | type = TREE_TYPE (type); |
---|
390 | |
---|
391 | if (!TYPE_VIRTUAL_P (type) || CLASSTYPE_VFIELD (type) == NULL_TREE) |
---|
392 | return exp; |
---|
393 | |
---|
394 | vptr = fold (size_binop (PLUS_EXPR, |
---|
395 | size_binop (FLOOR_DIV_EXPR, |
---|
396 | DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (type)), |
---|
397 | size_int (BITS_PER_UNIT)), |
---|
398 | exp)); |
---|
399 | vptr = build1 (INDIRECT_REF, build_pointer_type (vtable_entry_type), vptr); |
---|
400 | |
---|
401 | if (flag_vtable_thunks) |
---|
402 | offset = build_array_ref (vptr, integer_zero_node); |
---|
403 | else |
---|
404 | offset = build_component_ref (build_array_ref (vptr, integer_zero_node), |
---|
405 | delta_identifier, |
---|
406 | NULL_TREE, 0); |
---|
407 | |
---|
408 | type = build_type_variant (ptr_type_node, TREE_READONLY (exp), |
---|
409 | TREE_THIS_VOLATILE (exp)); |
---|
410 | return build (PLUS_EXPR, type, exp, |
---|
411 | convert (ptrdiff_type_node, offset)); |
---|
412 | } |
---|
413 | |
---|
414 | /* Return the type_info node associated with the expression EXP. If EXP is |
---|
415 | a reference to a polymorphic class, return the dynamic type; otherwise |
---|
416 | return the static type of the expression. */ |
---|
417 | tree |
---|
418 | build_typeid (exp) |
---|
419 | tree exp; |
---|
420 | { |
---|
421 | tree type; |
---|
422 | |
---|
423 | if (!flag_rtti) |
---|
424 | cp_error ("cannot take typeid of object when -frtti is not specified"); |
---|
425 | |
---|
426 | if (exp == error_mark_node) |
---|
427 | return error_mark_node; |
---|
428 | |
---|
429 | type = TREE_TYPE (exp); |
---|
430 | |
---|
431 | /* Strip top-level cv-qualifiers. */ |
---|
432 | type = TYPE_MAIN_VARIANT (type); |
---|
433 | |
---|
434 | /* if b is an instance of B, typeid(b) == typeid(B). Do this before |
---|
435 | reference trickiness. */ |
---|
436 | if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE) |
---|
437 | return get_typeid (type); |
---|
438 | |
---|
439 | /* peel back references, so they match. */ |
---|
440 | if (TREE_CODE (type) == REFERENCE_TYPE) |
---|
441 | type = TREE_TYPE (type); |
---|
442 | |
---|
443 | /* Peel off cv qualifiers. */ |
---|
444 | type = TYPE_MAIN_VARIANT (type); |
---|
445 | |
---|
446 | /* Apply trivial conversion T -> T& for dereferenced ptrs. */ |
---|
447 | if (TREE_CODE (type) == RECORD_TYPE) |
---|
448 | type = build_reference_type (type); |
---|
449 | |
---|
450 | /* If exp is a reference to polymorphic type, get the real type_info. */ |
---|
451 | if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type))) |
---|
452 | { |
---|
453 | /* build reference to type_info from vtable. */ |
---|
454 | tree t; |
---|
455 | |
---|
456 | if (flag_vtable_thunks) |
---|
457 | t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_one_node); |
---|
458 | else |
---|
459 | t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_zero_node); |
---|
460 | |
---|
461 | TREE_TYPE (t) = build_pointer_type (__class_desc_type_node); |
---|
462 | t = build_indirect_ref (t, NULL); |
---|
463 | return t; |
---|
464 | } |
---|
465 | |
---|
466 | /* otherwise return the type_info for the static type of the expr. */ |
---|
467 | return get_typeid (type); |
---|
468 | } |
---|
469 | |
---|
470 | /* Return the type_info object for TYPE, creating it if necessary. */ |
---|
471 | tree |
---|
472 | get_typeid (type) |
---|
473 | tree type; |
---|
474 | { |
---|
475 | tree t, td; |
---|
476 | |
---|
477 | if (type == error_mark_node) |
---|
478 | return error_mark_node; |
---|
479 | |
---|
480 | /* Is it useful (and/or correct) to have different typeids for `T &' |
---|
481 | and `T'? */ |
---|
482 | if (TREE_CODE (type) == REFERENCE_TYPE) |
---|
483 | type = TREE_TYPE (type); |
---|
484 | |
---|
485 | td = build_t_desc (type, 1); |
---|
486 | if (td == error_mark_node) |
---|
487 | return error_mark_node; |
---|
488 | |
---|
489 | t = TREE_OPERAND (td, 0); |
---|
490 | return t; |
---|
491 | } |
---|
492 | |
---|
493 | /* Get a bad_cast node for the program to throw... |
---|
494 | |
---|
495 | See libstdc++::exception{,.cc} for __bad_cast_object */ |
---|
496 | tree |
---|
497 | get_bad_cast_node () |
---|
498 | { |
---|
499 | static tree t; |
---|
500 | if (t == NULL_TREE |
---|
501 | && (t = lookup_name (get_identifier ("__bad_cast_object"), 0)) |
---|
502 | == NULL_TREE) |
---|
503 | { |
---|
504 | error ("you must #include <typeinfo>"); |
---|
505 | return error_mark_node; |
---|
506 | } |
---|
507 | return t; |
---|
508 | } |
---|
509 | |
---|
510 | /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working |
---|
511 | paper. */ |
---|
512 | tree |
---|
513 | build_dynamic_cast (type, expr) |
---|
514 | tree type, expr; |
---|
515 | { |
---|
516 | enum tree_code tc = TREE_CODE (type); |
---|
517 | tree exprtype = TREE_TYPE (expr); |
---|
518 | enum tree_code ec = TREE_CODE (exprtype); |
---|
519 | tree retval; |
---|
520 | |
---|
521 | if (type == error_mark_node || expr == error_mark_node) |
---|
522 | return error_mark_node; |
---|
523 | |
---|
524 | switch (tc) |
---|
525 | { |
---|
526 | case POINTER_TYPE: |
---|
527 | if (ec == REFERENCE_TYPE) |
---|
528 | { |
---|
529 | expr = convert_from_reference (expr); |
---|
530 | exprtype = TREE_TYPE (expr); |
---|
531 | ec = TREE_CODE (exprtype); |
---|
532 | } |
---|
533 | if (ec != POINTER_TYPE) |
---|
534 | goto fail; |
---|
535 | if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) |
---|
536 | goto fail; |
---|
537 | if (TYPE_SIZE (TREE_TYPE (exprtype)) == 0) |
---|
538 | goto fail; |
---|
539 | if (TREE_READONLY (TREE_TYPE (exprtype)) && |
---|
540 | ! TYPE_READONLY (TREE_TYPE (type))) |
---|
541 | goto fail; |
---|
542 | if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) |
---|
543 | break; |
---|
544 | /* else fall through */ |
---|
545 | case REFERENCE_TYPE: |
---|
546 | if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE |
---|
547 | && TYPE_SIZE (TREE_TYPE (type)) != NULL_TREE) |
---|
548 | break; |
---|
549 | /* else fall through */ |
---|
550 | default: |
---|
551 | goto fail; |
---|
552 | } |
---|
553 | |
---|
554 | /* Apply trivial conversion T -> T& for dereferenced ptrs. */ |
---|
555 | if (ec == RECORD_TYPE) |
---|
556 | { |
---|
557 | exprtype = build_type_variant (exprtype, TREE_READONLY (expr), |
---|
558 | TREE_THIS_VOLATILE (expr)); |
---|
559 | exprtype = build_reference_type (exprtype); |
---|
560 | expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT, |
---|
561 | LOOKUP_NORMAL, NULL_TREE); |
---|
562 | ec = REFERENCE_TYPE; |
---|
563 | } |
---|
564 | |
---|
565 | if (tc == REFERENCE_TYPE) |
---|
566 | { |
---|
567 | if (ec != REFERENCE_TYPE) |
---|
568 | goto fail; |
---|
569 | if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) |
---|
570 | goto fail; |
---|
571 | if (TYPE_SIZE (TREE_TYPE (exprtype)) == 0) |
---|
572 | goto fail; |
---|
573 | } |
---|
574 | |
---|
575 | /* If *type is an unambiguous accessible base class of *exprtype, |
---|
576 | convert statically. */ |
---|
577 | { |
---|
578 | int distance; |
---|
579 | tree path; |
---|
580 | |
---|
581 | distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1, |
---|
582 | &path); |
---|
583 | if (distance >= 0) |
---|
584 | return build_vbase_path (PLUS_EXPR, type, expr, path, 0); |
---|
585 | } |
---|
586 | |
---|
587 | /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */ |
---|
588 | if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype))) |
---|
589 | { |
---|
590 | /* if TYPE is `void *', return pointer to complete object. */ |
---|
591 | if (tc == POINTER_TYPE |
---|
592 | && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) |
---|
593 | { |
---|
594 | /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */ |
---|
595 | if (TREE_CODE (expr) == ADDR_EXPR |
---|
596 | && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL |
---|
597 | && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE) |
---|
598 | return build1 (NOP_EXPR, type, expr); |
---|
599 | |
---|
600 | return build_headof (expr); |
---|
601 | } |
---|
602 | else |
---|
603 | { |
---|
604 | tree retval; |
---|
605 | tree result, td1, td2, elems, tmp1, expr1; |
---|
606 | |
---|
607 | /* If we got here, we can't convert statically. Therefore, |
---|
608 | dynamic_cast<D&>(b) (b an object) cannot succeed. */ |
---|
609 | if (ec == REFERENCE_TYPE) |
---|
610 | { |
---|
611 | if (TREE_CODE (expr) == VAR_DECL |
---|
612 | && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE) |
---|
613 | { |
---|
614 | cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", |
---|
615 | expr, type); |
---|
616 | return build_throw (get_bad_cast_node ()); |
---|
617 | } |
---|
618 | } |
---|
619 | /* Ditto for dynamic_cast<D*>(&b). */ |
---|
620 | else if (TREE_CODE (expr) == ADDR_EXPR) |
---|
621 | { |
---|
622 | tree op = TREE_OPERAND (expr, 0); |
---|
623 | if (TREE_CODE (op) == VAR_DECL |
---|
624 | && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE) |
---|
625 | { |
---|
626 | cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", |
---|
627 | expr, type); |
---|
628 | retval = build_int_2 (0, 0); |
---|
629 | TREE_TYPE (retval) = type; |
---|
630 | return retval; |
---|
631 | } |
---|
632 | } |
---|
633 | |
---|
634 | expr1 = expr; |
---|
635 | if (tc == REFERENCE_TYPE) |
---|
636 | expr1 = build_unary_op (ADDR_EXPR, expr1, 0); |
---|
637 | |
---|
638 | /* Build run-time conversion. */ |
---|
639 | expr1 = build_headof (expr1); |
---|
640 | |
---|
641 | if (ec == POINTER_TYPE) |
---|
642 | td1 = build_typeid (build_indirect_ref (expr, NULL_PTR)); |
---|
643 | else |
---|
644 | td1 = build_typeid (expr); |
---|
645 | |
---|
646 | if (tc == POINTER_TYPE) |
---|
647 | td2 = get_typeid (TREE_TYPE (type)); |
---|
648 | else |
---|
649 | td2 = get_typeid (type); |
---|
650 | |
---|
651 | elems = tree_cons (NULL_TREE, td2, |
---|
652 | tree_cons (NULL_TREE, build_int_2 (1, 0), |
---|
653 | tree_cons (NULL_TREE, expr1, NULL_TREE))); |
---|
654 | result = build_method_call (td1, |
---|
655 | get_identifier ("__rtti_match"), elems, NULL_TREE, LOOKUP_NORMAL); |
---|
656 | |
---|
657 | if (tc == REFERENCE_TYPE) |
---|
658 | { |
---|
659 | expr1 = build_throw (get_bad_cast_node ()); |
---|
660 | expr1 = build_compound_expr (tree_cons (NULL_TREE, expr1, |
---|
661 | build_tree_list (NULL_TREE, convert (type, integer_zero_node)))); |
---|
662 | TREE_TYPE (expr1) = type; |
---|
663 | return build (COND_EXPR, type, result, result, expr1); |
---|
664 | } |
---|
665 | |
---|
666 | /* Now back to the type we want from a void*. */ |
---|
667 | result = convert (type, result); |
---|
668 | return result; |
---|
669 | } |
---|
670 | } |
---|
671 | |
---|
672 | fail: |
---|
673 | cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'", |
---|
674 | expr, exprtype, type); |
---|
675 | return error_mark_node; |
---|
676 | } |
---|
677 | |
---|
678 | /* Build and initialize various sorts of descriptors. Every descriptor |
---|
679 | node has a name associated with it (the name created by mangling). |
---|
680 | For this reason, we use the identifier as our access to the __*_desc |
---|
681 | nodes, instead of sticking them directly in the types. Otherwise we |
---|
682 | would burden all built-in types (and pointer types) with slots that |
---|
683 | we don't necessarily want to use. |
---|
684 | |
---|
685 | For each descriptor we build, we build a variable that contains |
---|
686 | the descriptor's information. When we need this info at runtime, |
---|
687 | all we need is access to these variables. |
---|
688 | |
---|
689 | Note: these constructors always return the address of the descriptor |
---|
690 | info, since that is simplest for their mutual interaction. */ |
---|
691 | |
---|
692 | static tree |
---|
693 | build_generic_desc (tdecl, type, elems) |
---|
694 | tree tdecl; |
---|
695 | tree type; |
---|
696 | tree elems; |
---|
697 | { |
---|
698 | tree init = elems; |
---|
699 | int toplev = global_bindings_p (); |
---|
700 | |
---|
701 | TREE_CONSTANT (init) = 1; |
---|
702 | TREE_STATIC (init) = 1; |
---|
703 | TREE_READONLY (init) = 1; |
---|
704 | |
---|
705 | TREE_TYPE (tdecl) = type; |
---|
706 | DECL_INITIAL (tdecl) = init; |
---|
707 | TREE_STATIC (tdecl) = 1; |
---|
708 | DECL_SIZE (tdecl) = NULL_TREE; |
---|
709 | layout_decl (tdecl, 0); |
---|
710 | if (! toplev) |
---|
711 | push_to_top_level (); |
---|
712 | cp_finish_decl (tdecl, init, NULL_TREE, 0, 0); |
---|
713 | if (! toplev) |
---|
714 | pop_from_top_level (); |
---|
715 | |
---|
716 | if (! TREE_USED (tdecl)) |
---|
717 | { |
---|
718 | assemble_external (tdecl); |
---|
719 | TREE_USED (tdecl) = 1; |
---|
720 | } |
---|
721 | |
---|
722 | return IDENTIFIER_AS_DESC (DECL_NAME (tdecl)); |
---|
723 | } |
---|
724 | |
---|
725 | /* Build an initializer for a __bltn_desc node. */ |
---|
726 | static tree |
---|
727 | build_bltn_desc (tdecl, type) |
---|
728 | tree tdecl; |
---|
729 | tree type; |
---|
730 | { |
---|
731 | tree elems, t; |
---|
732 | |
---|
733 | if (type == boolean_type_node) |
---|
734 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_BOOL"), |
---|
735 | 0, 0); |
---|
736 | else if (type == char_type_node) |
---|
737 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_CHAR"), |
---|
738 | 0, 0); |
---|
739 | else if (type == short_integer_type_node) |
---|
740 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SHORT"), |
---|
741 | 0, 0); |
---|
742 | else if (type == integer_type_node) |
---|
743 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_INT"), |
---|
744 | 0, 0); |
---|
745 | else if (type == long_integer_type_node) |
---|
746 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_LONG"), |
---|
747 | 0, 0); |
---|
748 | else if (type == long_long_integer_type_node) |
---|
749 | t = lookup_field (__bltn_desc_type_node, |
---|
750 | get_identifier("_RTTI_BI_LONGLONG"), 0, 0); |
---|
751 | else if (type == float_type_node) |
---|
752 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_FLOAT"), |
---|
753 | 0, 0); |
---|
754 | else if (type == double_type_node) |
---|
755 | t = lookup_field (__bltn_desc_type_node, |
---|
756 | get_identifier("_RTTI_BI_DOUBLE"), 0, 0); |
---|
757 | else if (type == long_double_type_node) |
---|
758 | t = lookup_field (__bltn_desc_type_node, |
---|
759 | get_identifier("_RTTI_BI_LDOUBLE"), 0, 0); |
---|
760 | else if (type == unsigned_char_type_node) |
---|
761 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UCHAR"), |
---|
762 | 0, 0); |
---|
763 | else if (type == short_unsigned_type_node) |
---|
764 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_USHORT"), |
---|
765 | 0, 0); |
---|
766 | else if (type == unsigned_type_node) |
---|
767 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UINT"), |
---|
768 | 0, 0); |
---|
769 | else if (type == long_unsigned_type_node) |
---|
770 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_ULONG"), |
---|
771 | 0, 0); |
---|
772 | else if (type == long_long_unsigned_type_node) |
---|
773 | t = lookup_field (__bltn_desc_type_node, |
---|
774 | get_identifier("_RTTI_BI_ULONGLONG"), 0, 0); |
---|
775 | else if (type == signed_char_type_node) |
---|
776 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SCHAR"), |
---|
777 | 0, 0); |
---|
778 | else if (type == wchar_type_node) |
---|
779 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_WCHAR"), |
---|
780 | 0, 0); |
---|
781 | else if (type == void_type_node) |
---|
782 | t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_VOID"), |
---|
783 | 0, 0); |
---|
784 | else |
---|
785 | { |
---|
786 | cp_compiler_error ("type `%T' not handled as a built-in type"); |
---|
787 | } |
---|
788 | |
---|
789 | elems = tree_cons (NULL_TREE, t, NULL_TREE); |
---|
790 | return build_generic_desc (tdecl, __bltn_desc_type_node, elems); |
---|
791 | } |
---|
792 | |
---|
793 | /* Build an initializer for a __user_desc node. */ |
---|
794 | static tree |
---|
795 | build_user_desc (tdecl) |
---|
796 | tree tdecl; |
---|
797 | { |
---|
798 | tree elems, name_string, t; |
---|
799 | tree tname = DECL_NAME (tdecl); |
---|
800 | |
---|
801 | name_string = combine_strings (build_string |
---|
802 | (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); |
---|
803 | elems = name_string; |
---|
804 | return build_generic_desc (tdecl, __user_desc_type_node, elems); |
---|
805 | } |
---|
806 | |
---|
807 | /* Build an initializer for a __class_type_info node. */ |
---|
808 | static tree |
---|
809 | build_class_desc (tdecl, type) |
---|
810 | tree tdecl; |
---|
811 | tree type; |
---|
812 | { |
---|
813 | tree tname = DECL_NAME (tdecl); |
---|
814 | tree name_string; |
---|
815 | |
---|
816 | int i = CLASSTYPE_N_BASECLASSES (type); |
---|
817 | int n_base = i; |
---|
818 | int base_cnt = 0; |
---|
819 | tree binfos = TYPE_BINFO_BASETYPES (type); |
---|
820 | tree vb = CLASSTYPE_VBASECLASSES (type); |
---|
821 | tree base, elems, access, offset, isvir; |
---|
822 | tree base_list, off_list, acc_list, isvir_list; |
---|
823 | tree t; |
---|
824 | static tree acc_pub = NULL_TREE; |
---|
825 | static tree acc_pro = NULL_TREE; |
---|
826 | static tree acc_pri = NULL_TREE; |
---|
827 | |
---|
828 | if (acc_pub == NULL_TREE) |
---|
829 | { |
---|
830 | acc_pub = lookup_field (__class_desc_type_node, |
---|
831 | get_identifier("_RTTI_ACCESS_PUBLIC"), 0, 0); |
---|
832 | acc_pro = lookup_field (__class_desc_type_node, |
---|
833 | get_identifier("_RTTI_ACCESS_PROTECTED"), 0, 0); |
---|
834 | acc_pri = lookup_field (__class_desc_type_node, |
---|
835 | get_identifier("_RTTI_ACCESS_PRIVATE"), 0, 0); |
---|
836 | } |
---|
837 | |
---|
838 | base_list = build_tree_list (NULL_TREE, integer_zero_node); |
---|
839 | off_list = build_tree_list (NULL_TREE, integer_zero_node); |
---|
840 | acc_list = build_tree_list (NULL_TREE, integer_zero_node); |
---|
841 | isvir_list = build_tree_list (NULL_TREE, integer_zero_node); |
---|
842 | while (--i >= 0) |
---|
843 | { |
---|
844 | tree binfo = TREE_VEC_ELT (binfos, i); |
---|
845 | |
---|
846 | base = build_t_desc (BINFO_TYPE (binfo), 1); |
---|
847 | if (TREE_VIA_VIRTUAL (binfo)) |
---|
848 | { |
---|
849 | tree t = BINFO_TYPE (binfo); |
---|
850 | char *name; |
---|
851 | tree field; |
---|
852 | int off; |
---|
853 | |
---|
854 | name = (char *) alloca (TYPE_NAME_LENGTH (t)+sizeof (VBASE_NAME)+1); |
---|
855 | sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (t)); |
---|
856 | field = lookup_field (type, get_identifier (name), 0, 0); |
---|
857 | offset = size_binop (FLOOR_DIV_EXPR, |
---|
858 | DECL_FIELD_BITPOS (field), size_int (BITS_PER_UNIT)); |
---|
859 | } |
---|
860 | else |
---|
861 | offset = BINFO_OFFSET (binfo); |
---|
862 | |
---|
863 | if (TREE_VIA_PUBLIC (binfo)) |
---|
864 | access = acc_pub; |
---|
865 | else if (TREE_VIA_PROTECTED (binfo)) |
---|
866 | access = acc_pro; |
---|
867 | else |
---|
868 | access = acc_pri; |
---|
869 | if (TREE_VIA_VIRTUAL (binfo)) |
---|
870 | isvir = build_int_2 (1, 0); |
---|
871 | else |
---|
872 | isvir = build_int_2 (0, 0); |
---|
873 | |
---|
874 | base_list = tree_cons (NULL_TREE, base, base_list); |
---|
875 | isvir_list = tree_cons (NULL_TREE, isvir, isvir_list); |
---|
876 | acc_list = tree_cons (NULL_TREE, access, acc_list); |
---|
877 | off_list = tree_cons (NULL_TREE, offset, off_list); |
---|
878 | base_cnt++; |
---|
879 | } |
---|
880 | #if 0 |
---|
881 | i = n_base; |
---|
882 | while (vb) |
---|
883 | { |
---|
884 | tree b; |
---|
885 | access = acc_pub; |
---|
886 | while (--i >= 0) |
---|
887 | { |
---|
888 | b = TREE_VEC_ELT (binfos, i); |
---|
889 | if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b)) |
---|
890 | { |
---|
891 | if (TREE_VIA_PUBLIC (b)) |
---|
892 | access = acc_pub; |
---|
893 | else if (TREE_VIA_PROTECTED (b)) |
---|
894 | access = acc_pro; |
---|
895 | else |
---|
896 | access = acc_pri; |
---|
897 | break; |
---|
898 | } |
---|
899 | } |
---|
900 | base = build_t_desc (BINFO_TYPE (vb), 1); |
---|
901 | offset = BINFO_OFFSET (vb); |
---|
902 | isvir = build_int_2 (1, 0); |
---|
903 | |
---|
904 | base_list = tree_cons (NULL_TREE, base, base_list); |
---|
905 | isvir_list = tree_cons (NULL_TREE, isvir, isvir_list); |
---|
906 | acc_list = tree_cons (NULL_TREE, access, acc_list); |
---|
907 | off_list = tree_cons (NULL_TREE, offset, off_list); |
---|
908 | |
---|
909 | base_cnt++; |
---|
910 | vb = TREE_CHAIN (vb); |
---|
911 | } |
---|
912 | #endif |
---|
913 | base_list = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), |
---|
914 | base_list, 0); |
---|
915 | off_list = finish_table (NULL_TREE, integer_type_node, |
---|
916 | off_list, 0); |
---|
917 | isvir_list = finish_table (NULL_TREE, integer_type_node, |
---|
918 | isvir_list, 0); |
---|
919 | acc_list = finish_table (NULL_TREE, __access_mode_type_node, |
---|
920 | acc_list, 0); |
---|
921 | |
---|
922 | |
---|
923 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); |
---|
924 | |
---|
925 | elems = tree_cons (NULL_TREE, name_string, |
---|
926 | tree_cons (NULL_TREE, default_conversion (base_list), |
---|
927 | tree_cons (NULL_TREE, default_conversion (off_list), |
---|
928 | tree_cons (NULL_TREE, default_conversion (isvir_list), |
---|
929 | tree_cons (NULL_TREE, default_conversion (acc_list), |
---|
930 | tree_cons (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE)))))); |
---|
931 | |
---|
932 | return build_generic_desc (tdecl, __class_desc_type_node, elems); |
---|
933 | } |
---|
934 | |
---|
935 | /* Build an initializer for a __pointer_type_info node. */ |
---|
936 | static tree |
---|
937 | build_ptr_desc (tdecl, type) |
---|
938 | tree tdecl; |
---|
939 | tree type; |
---|
940 | { |
---|
941 | tree t, elems; |
---|
942 | |
---|
943 | t = TREE_TYPE (type); |
---|
944 | t = build_t_desc (t, 1); |
---|
945 | t = build_indirect_ref (t, NULL); |
---|
946 | elems = tree_cons (NULL_TREE, t, NULL_TREE); |
---|
947 | return build_generic_desc (tdecl, __ptr_desc_type_node, elems); |
---|
948 | } |
---|
949 | |
---|
950 | /* Build an initializer for a __attr_type_info node. */ |
---|
951 | static tree |
---|
952 | build_attr_desc (tdecl, type) |
---|
953 | tree tdecl; |
---|
954 | tree type; |
---|
955 | { |
---|
956 | tree elems, t, attrval; |
---|
957 | |
---|
958 | if (TYPE_READONLY (type)) |
---|
959 | { |
---|
960 | if (TYPE_VOLATILE (type)) |
---|
961 | attrval = lookup_field (__attr_desc_type_node, |
---|
962 | get_identifier("_RTTI_ATTR_CONSTVOL"), 0, 0); |
---|
963 | else |
---|
964 | attrval = lookup_field (__attr_desc_type_node, |
---|
965 | get_identifier("_RTTI_ATTR_CONST"), 0, 0); |
---|
966 | } |
---|
967 | else |
---|
968 | { |
---|
969 | if (TYPE_VOLATILE (type)) |
---|
970 | attrval = lookup_field (__attr_desc_type_node, |
---|
971 | get_identifier("_RTTI_ATTR_VOLATILE"), 0, 0); |
---|
972 | } |
---|
973 | t = build_t_desc (TYPE_MAIN_VARIANT (type), 1); |
---|
974 | t = build_indirect_ref (t , NULL); |
---|
975 | elems = tree_cons (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE)); |
---|
976 | return build_generic_desc (tdecl, __attr_desc_type_node, elems); |
---|
977 | } |
---|
978 | |
---|
979 | /* Build an initializer for a __func_type_info node. */ |
---|
980 | static tree |
---|
981 | build_func_desc (tdecl) |
---|
982 | tree tdecl; |
---|
983 | { |
---|
984 | tree elems, name_string; |
---|
985 | tree tname = DECL_NAME (tdecl); |
---|
986 | |
---|
987 | name_string = combine_strings (build_string |
---|
988 | (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); |
---|
989 | elems = name_string; |
---|
990 | return build_generic_desc (tdecl, __func_desc_type_node, elems); |
---|
991 | } |
---|
992 | |
---|
993 | /* Build an initializer for a __ptmf_type_info node. */ |
---|
994 | static tree |
---|
995 | build_ptmf_desc (tdecl, type) |
---|
996 | tree tdecl; |
---|
997 | tree type; |
---|
998 | { |
---|
999 | tree elems, name_string; |
---|
1000 | tree tname = DECL_NAME (tdecl); |
---|
1001 | |
---|
1002 | name_string = combine_strings (build_string |
---|
1003 | (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); |
---|
1004 | elems = name_string; |
---|
1005 | return build_generic_desc (tdecl, __ptmf_desc_type_node, elems); |
---|
1006 | } |
---|
1007 | |
---|
1008 | /* Build an initializer for a __ptmd_type_info node. */ |
---|
1009 | static tree |
---|
1010 | build_ptmd_desc (tdecl, type) |
---|
1011 | tree tdecl; |
---|
1012 | tree type; |
---|
1013 | { |
---|
1014 | tree tc, t, elems; |
---|
1015 | tc = build_t_desc (TYPE_OFFSET_BASETYPE (type), 1); |
---|
1016 | tc = build_indirect_ref (tc , NULL); |
---|
1017 | t = build_t_desc (TREE_TYPE (type), 1); |
---|
1018 | t = build_indirect_ref (t , NULL); |
---|
1019 | elems = tree_cons (NULL_TREE, tc, |
---|
1020 | tree_cons (NULL_TREE, t, NULL_TREE)); |
---|
1021 | return build_generic_desc (tdecl, __ptmd_desc_type_node, elems); |
---|
1022 | } |
---|
1023 | |
---|
1024 | struct uninst_st { |
---|
1025 | tree type; |
---|
1026 | struct uninst_st *next; |
---|
1027 | }; |
---|
1028 | typedef struct uninst_st uninst_node; |
---|
1029 | static uninst_node * uninst_desc = (uninst_node *)NULL; |
---|
1030 | |
---|
1031 | static void |
---|
1032 | add_uninstantiated_desc (type) |
---|
1033 | tree type; |
---|
1034 | { |
---|
1035 | uninst_node *t; |
---|
1036 | |
---|
1037 | t = (uninst_node *) xmalloc (sizeof (struct uninst_st)); |
---|
1038 | t->type = type; |
---|
1039 | t->next = uninst_desc; |
---|
1040 | uninst_desc = t; |
---|
1041 | } |
---|
1042 | |
---|
1043 | /* We may choose to link the emitting of certain high use TDs for certain |
---|
1044 | objects, we do that here. Return the type to link against if such a |
---|
1045 | link exists, otherwise just return TYPE. */ |
---|
1046 | |
---|
1047 | tree |
---|
1048 | get_def_to_follow (type) |
---|
1049 | tree type; |
---|
1050 | { |
---|
1051 | #if 0 |
---|
1052 | /* For now we don't lay out T&, T* TDs with the main TD for the object. */ |
---|
1053 | /* Let T* and T& be written only when T is written (if T is an aggr). |
---|
1054 | We do this for const, but not for volatile, since volatile |
---|
1055 | is rare and const is not. */ |
---|
1056 | if (!TYPE_VOLATILE (taggr) |
---|
1057 | && (TREE_CODE (taggr) == POINTER_TYPE |
---|
1058 | || TREE_CODE (taggr) == REFERENCE_TYPE) |
---|
1059 | && IS_AGGR_TYPE (TREE_TYPE (taggr))) |
---|
1060 | taggr = TREE_TYPE (taggr); |
---|
1061 | #endif |
---|
1062 | return type; |
---|
1063 | } |
---|
1064 | |
---|
1065 | /* build a general type_info node. */ |
---|
1066 | tree |
---|
1067 | build_t_desc (type, definition) |
---|
1068 | tree type; |
---|
1069 | int definition; |
---|
1070 | { |
---|
1071 | tree tdecl; |
---|
1072 | tree tname, name_string; |
---|
1073 | tree elems; |
---|
1074 | tree t, tt, taggr; |
---|
1075 | |
---|
1076 | if (__ptmd_desc_type_node == NULL_TREE) |
---|
1077 | { |
---|
1078 | init_type_desc(); |
---|
1079 | if (__ptmd_desc_type_node) |
---|
1080 | { |
---|
1081 | for ( ; uninst_desc; uninst_desc = uninst_desc->next ) |
---|
1082 | build_t_desc (uninst_desc->type, 1); |
---|
1083 | } |
---|
1084 | } |
---|
1085 | if (__t_desc_type_node == NULL_TREE) |
---|
1086 | { |
---|
1087 | static int warned = 0; |
---|
1088 | if (! warned) |
---|
1089 | { |
---|
1090 | cp_error ("failed to build type descriptor node of '%T', maybe typeinfo.h not included", type); |
---|
1091 | } |
---|
1092 | warned = 1; |
---|
1093 | return error_mark_node; |
---|
1094 | } |
---|
1095 | if (__ptmd_desc_type_node == NULL_TREE) |
---|
1096 | { |
---|
1097 | add_uninstantiated_desc (type); |
---|
1098 | definition = 0; |
---|
1099 | } |
---|
1100 | |
---|
1101 | push_obstacks (&permanent_obstack, &permanent_obstack); |
---|
1102 | tname = build_t_desc_overload (type); |
---|
1103 | |
---|
1104 | if (!IDENTIFIER_AS_DESC (tname)) |
---|
1105 | { |
---|
1106 | tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); |
---|
1107 | DECL_EXTERNAL (tdecl) = 1; |
---|
1108 | TREE_PUBLIC (tdecl) = 1; |
---|
1109 | tdecl = pushdecl_top_level (tdecl); |
---|
1110 | SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); |
---|
1111 | if (!definition) |
---|
1112 | cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); |
---|
1113 | } |
---|
1114 | else |
---|
1115 | tdecl = TREE_OPERAND (IDENTIFIER_AS_DESC (tname), 0); |
---|
1116 | |
---|
1117 | /* If it's not a definition, don't do anything more. */ |
---|
1118 | if (!definition) |
---|
1119 | return IDENTIFIER_AS_DESC (tname); |
---|
1120 | |
---|
1121 | /* If it has already been written, don't to anything more. */ |
---|
1122 | /* Should this be on tdecl? */ |
---|
1123 | if (TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname))) |
---|
1124 | return IDENTIFIER_AS_DESC (tname); |
---|
1125 | |
---|
1126 | /* If we previously defined it, return the defined result. */ |
---|
1127 | if (DECL_INITIAL (tdecl)) |
---|
1128 | return IDENTIFIER_AS_DESC (tname); |
---|
1129 | |
---|
1130 | taggr = get_def_to_follow (type); |
---|
1131 | |
---|
1132 | /* If we know that we don't need to write out this type's |
---|
1133 | vtable, then don't write out it's type_info. Somebody |
---|
1134 | else will take care of that. */ |
---|
1135 | if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) |
---|
1136 | { |
---|
1137 | /* Let's play follow the vtable. */ |
---|
1138 | TREE_PUBLIC (tdecl) = CLASSTYPE_INTERFACE_KNOWN (taggr); |
---|
1139 | DECL_EXTERNAL (tdecl) = CLASSTYPE_INTERFACE_ONLY (taggr); |
---|
1140 | } |
---|
1141 | else |
---|
1142 | { |
---|
1143 | DECL_EXTERNAL (tdecl) = 0; |
---|
1144 | TREE_PUBLIC (tdecl) = (definition > 1); |
---|
1145 | } |
---|
1146 | |
---|
1147 | if (DECL_EXTERNAL (tdecl)) |
---|
1148 | return IDENTIFIER_AS_DESC (tname); |
---|
1149 | |
---|
1150 | /* Show that we are defining the t_desc for this type. */ |
---|
1151 | DECL_INITIAL (tdecl) = error_mark_node; |
---|
1152 | t = DECL_CONTEXT (tdecl); |
---|
1153 | if ( t && TREE_CODE_CLASS (TREE_CODE (t)) == 't') |
---|
1154 | pushclass (t, 2); |
---|
1155 | |
---|
1156 | if (TYPE_VOLATILE (type) || TYPE_READONLY (type)) |
---|
1157 | t = build_attr_desc (tdecl, type); |
---|
1158 | else if (TREE_CODE (type) == ARRAY_TYPE) |
---|
1159 | t = build_ptr_desc (tdecl, type); |
---|
1160 | else if (TREE_CODE (type) == POINTER_TYPE) |
---|
1161 | { |
---|
1162 | if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE) |
---|
1163 | { |
---|
1164 | type = TREE_TYPE (type); |
---|
1165 | t = build_ptmd_desc (tdecl, type); |
---|
1166 | } |
---|
1167 | else |
---|
1168 | { |
---|
1169 | t = build_ptr_desc (tdecl, type); |
---|
1170 | } |
---|
1171 | } |
---|
1172 | else if (TYPE_BUILT_IN (type)) |
---|
1173 | t = build_bltn_desc (tdecl, type); |
---|
1174 | else if (IS_AGGR_TYPE (type)) |
---|
1175 | { |
---|
1176 | if (TYPE_PTRMEMFUNC_P (type)) |
---|
1177 | { |
---|
1178 | t = build_ptmf_desc (tdecl, type); |
---|
1179 | } |
---|
1180 | else |
---|
1181 | { |
---|
1182 | t = build_class_desc (tdecl, type); |
---|
1183 | } |
---|
1184 | } |
---|
1185 | else if (TREE_CODE (type) == FUNCTION_TYPE) |
---|
1186 | t = build_func_desc (tdecl); |
---|
1187 | else |
---|
1188 | t = build_user_desc (tdecl); |
---|
1189 | |
---|
1190 | pop_obstacks (); |
---|
1191 | return t; |
---|
1192 | } |
---|
1193 | |
---|
1194 | #if 0 |
---|
1195 | /* This is the old dossier type descriptor generation code, it's much |
---|
1196 | more extended than rtti. It's reserved for later use. */ |
---|
1197 | /* Build an initializer for a __t_desc node. So that we can take advantage |
---|
1198 | of recursion, we accept NULL for TYPE. |
---|
1199 | DEFINITION is greater than zero iff we must define the type descriptor |
---|
1200 | (as opposed to merely referencing it). 1 means treat according to |
---|
1201 | #pragma interface/#pragma implementation rules. 2 means define as |
---|
1202 | global and public, no matter what. */ |
---|
1203 | tree |
---|
1204 | build_t_desc (type, definition) |
---|
1205 | tree type; |
---|
1206 | int definition; |
---|
1207 | { |
---|
1208 | tree tdecl; |
---|
1209 | tree tname, name_string; |
---|
1210 | tree elems, fields; |
---|
1211 | tree parents, vbases, offsets, ivars, methods, target_type; |
---|
1212 | int method_count = 0, field_count = 0; |
---|
1213 | |
---|
1214 | if (type == NULL_TREE) |
---|
1215 | return NULL_TREE; |
---|
1216 | |
---|
1217 | tname = build_t_desc_overload (type); |
---|
1218 | if (IDENTIFIER_AS_DESC (tname) |
---|
1219 | && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))) |
---|
1220 | return IDENTIFIER_AS_DESC (tname); |
---|
1221 | |
---|
1222 | tdecl = lookup_name (tname, 0); |
---|
1223 | if (tdecl == NULL_TREE) |
---|
1224 | { |
---|
1225 | tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); |
---|
1226 | DECL_EXTERNAL (tdecl) = 1; |
---|
1227 | TREE_PUBLIC (tdecl) = 1; |
---|
1228 | tdecl = pushdecl_top_level (tdecl); |
---|
1229 | } |
---|
1230 | /* If we previously defined it, return the defined result. */ |
---|
1231 | else if (definition && DECL_INITIAL (tdecl)) |
---|
1232 | return IDENTIFIER_AS_DESC (tname); |
---|
1233 | |
---|
1234 | if (definition) |
---|
1235 | { |
---|
1236 | tree taggr = type; |
---|
1237 | /* Let T* and T& be written only when T is written (if T is an aggr). |
---|
1238 | We do this for const, but not for volatile, since volatile |
---|
1239 | is rare and const is not. */ |
---|
1240 | if (!TYPE_VOLATILE (taggr) |
---|
1241 | && (TREE_CODE (taggr) == POINTER_TYPE |
---|
1242 | || TREE_CODE (taggr) == REFERENCE_TYPE) |
---|
1243 | && IS_AGGR_TYPE (TREE_TYPE (taggr))) |
---|
1244 | taggr = TREE_TYPE (taggr); |
---|
1245 | |
---|
1246 | /* If we know that we don't need to write out this type's |
---|
1247 | vtable, then don't write out it's dossier. Somebody |
---|
1248 | else will take care of that. */ |
---|
1249 | if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) |
---|
1250 | { |
---|
1251 | if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr)) |
---|
1252 | { |
---|
1253 | TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr) |
---|
1254 | && CLASSTYPE_INTERFACE_KNOWN (taggr); |
---|
1255 | DECL_EXTERNAL (tdecl) = 0; |
---|
1256 | } |
---|
1257 | else |
---|
1258 | { |
---|
1259 | if (write_virtuals != 0) |
---|
1260 | TREE_PUBLIC (tdecl) = 1; |
---|
1261 | } |
---|
1262 | } |
---|
1263 | else |
---|
1264 | { |
---|
1265 | DECL_EXTERNAL (tdecl) = 0; |
---|
1266 | TREE_PUBLIC (tdecl) = (definition > 1); |
---|
1267 | } |
---|
1268 | } |
---|
1269 | SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); |
---|
1270 | |
---|
1271 | if (!definition || DECL_EXTERNAL (tdecl)) |
---|
1272 | { |
---|
1273 | /* That's it! */ |
---|
1274 | cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0); |
---|
1275 | return IDENTIFIER_AS_DESC (tname); |
---|
1276 | } |
---|
1277 | |
---|
1278 | /* Show that we are defining the t_desc for this type. */ |
---|
1279 | DECL_INITIAL (tdecl) = error_mark_node; |
---|
1280 | |
---|
1281 | parents = build_tree_list (NULL_TREE, integer_zero_node); |
---|
1282 | vbases = build_tree_list (NULL_TREE, integer_zero_node); |
---|
1283 | offsets = build_tree_list (NULL_TREE, integer_zero_node); |
---|
1284 | methods = NULL_TREE; |
---|
1285 | ivars = NULL_TREE; |
---|
1286 | |
---|
1287 | if (TYPE_LANG_SPECIFIC (type)) |
---|
1288 | { |
---|
1289 | int i = CLASSTYPE_N_BASECLASSES (type); |
---|
1290 | tree method_vec = CLASSTYPE_METHOD_VEC (type); |
---|
1291 | tree *meth, *end; |
---|
1292 | tree binfos = TYPE_BINFO_BASETYPES (type); |
---|
1293 | tree vb = CLASSTYPE_VBASECLASSES (type); |
---|
1294 | |
---|
1295 | while (--i >= 0) |
---|
1296 | parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents); |
---|
1297 | |
---|
1298 | while (vb) |
---|
1299 | { |
---|
1300 | vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases); |
---|
1301 | offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets); |
---|
1302 | vb = TREE_CHAIN (vb); |
---|
1303 | } |
---|
1304 | |
---|
1305 | if (method_vec) |
---|
1306 | for (meth = TREE_VEC_END (method_vec), |
---|
1307 | end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; ) |
---|
1308 | if (*meth) |
---|
1309 | { |
---|
1310 | methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods); |
---|
1311 | method_count++; |
---|
1312 | } |
---|
1313 | } |
---|
1314 | |
---|
1315 | if (IS_AGGR_TYPE (type)) |
---|
1316 | { |
---|
1317 | for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) |
---|
1318 | if (TREE_CODE (fields) == FIELD_DECL |
---|
1319 | || TREE_CODE (fields) == VAR_DECL) |
---|
1320 | { |
---|
1321 | ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars); |
---|
1322 | field_count++; |
---|
1323 | } |
---|
1324 | ivars = nreverse (ivars); |
---|
1325 | } |
---|
1326 | |
---|
1327 | parents = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), parents, 0); |
---|
1328 | vbases = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), vbases, 0); |
---|
1329 | offsets = finish_table (NULL_TREE, integer_type_node, offsets, 0); |
---|
1330 | if (methods == NULL_TREE) |
---|
1331 | methods = null_pointer_node; |
---|
1332 | else |
---|
1333 | methods = build_unary_op (ADDR_EXPR, |
---|
1334 | finish_table (NULL_TREE, __m_desc_type_node, methods, 0), |
---|
1335 | 0); |
---|
1336 | if (ivars == NULL_TREE) |
---|
1337 | ivars = null_pointer_node; |
---|
1338 | else |
---|
1339 | ivars = build_unary_op (ADDR_EXPR, |
---|
1340 | finish_table (NULL_TREE, __i_desc_type_node, ivars, 0), |
---|
1341 | 0); |
---|
1342 | if (TREE_TYPE (type)) |
---|
1343 | target_type = build_t_desc (TREE_TYPE (type), definition); |
---|
1344 | else |
---|
1345 | target_type = integer_zero_node; |
---|
1346 | |
---|
1347 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); |
---|
1348 | |
---|
1349 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), |
---|
1350 | tree_cons (NULL_TREE, |
---|
1351 | TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node, |
---|
1352 | /* really should use bitfield initialization here. */ |
---|
1353 | tree_cons (NULL_TREE, integer_zero_node, |
---|
1354 | tree_cons (NULL_TREE, target_type, |
---|
1355 | tree_cons (NULL_TREE, build_int_2 (field_count, 2), |
---|
1356 | tree_cons (NULL_TREE, build_int_2 (method_count, 2), |
---|
1357 | tree_cons (NULL_TREE, ivars, |
---|
1358 | tree_cons (NULL_TREE, methods, |
---|
1359 | tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0), |
---|
1360 | tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0), |
---|
1361 | build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0)))))))))))); |
---|
1362 | return build_generic_desc (tdecl, elems); |
---|
1363 | } |
---|
1364 | |
---|
1365 | /* Build an initializer for a __i_desc node. */ |
---|
1366 | tree |
---|
1367 | build_i_desc (decl) |
---|
1368 | tree decl; |
---|
1369 | { |
---|
1370 | tree elems, name_string; |
---|
1371 | tree taggr; |
---|
1372 | |
---|
1373 | name_string = DECL_NAME (decl); |
---|
1374 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); |
---|
1375 | |
---|
1376 | /* Now decide whether this ivar should cause it's type to get |
---|
1377 | def'd or ref'd in this file. If the type we are looking at |
---|
1378 | has a proxy definition, we look at the proxy (i.e., a |
---|
1379 | `foo *' is equivalent to a `foo'). */ |
---|
1380 | taggr = TREE_TYPE (decl); |
---|
1381 | |
---|
1382 | if ((TREE_CODE (taggr) == POINTER_TYPE |
---|
1383 | || TREE_CODE (taggr) == REFERENCE_TYPE) |
---|
1384 | && TYPE_VOLATILE (taggr) == 0) |
---|
1385 | taggr = TREE_TYPE (taggr); |
---|
1386 | |
---|
1387 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), |
---|
1388 | tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl), |
---|
1389 | build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl), |
---|
1390 | ! IS_AGGR_TYPE (taggr))))); |
---|
1391 | taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems); |
---|
1392 | TREE_CONSTANT (taggr) = 1; |
---|
1393 | TREE_STATIC (taggr) = 1; |
---|
1394 | TREE_READONLY (taggr) = 1; |
---|
1395 | return taggr; |
---|
1396 | } |
---|
1397 | |
---|
1398 | /* Build an initializer for a __m_desc node. */ |
---|
1399 | tree |
---|
1400 | build_m_desc (decl) |
---|
1401 | tree decl; |
---|
1402 | { |
---|
1403 | tree taggr, elems, name_string; |
---|
1404 | tree parm_count, req_count, vindex, vcontext; |
---|
1405 | tree parms; |
---|
1406 | int p_count, r_count; |
---|
1407 | tree parm_types = NULL_TREE; |
---|
1408 | |
---|
1409 | for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0; |
---|
1410 | parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++) |
---|
1411 | { |
---|
1412 | taggr = TREE_VALUE (parms); |
---|
1413 | if ((TREE_CODE (taggr) == POINTER_TYPE |
---|
1414 | || TREE_CODE (taggr) == REFERENCE_TYPE) |
---|
1415 | && TYPE_VOLATILE (taggr) == 0) |
---|
1416 | taggr = TREE_TYPE (taggr); |
---|
1417 | |
---|
1418 | parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms), |
---|
1419 | ! IS_AGGR_TYPE (taggr)), |
---|
1420 | parm_types); |
---|
1421 | if (TREE_PURPOSE (parms) == NULL_TREE) |
---|
1422 | r_count++; |
---|
1423 | } |
---|
1424 | |
---|
1425 | parm_types = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node), |
---|
1426 | nreverse (parm_types), 0); |
---|
1427 | parm_count = build_int_2 (p_count, 0); |
---|
1428 | req_count = build_int_2 (r_count, 0); |
---|
1429 | |
---|
1430 | if (DECL_VINDEX (decl)) |
---|
1431 | vindex = DECL_VINDEX (decl); |
---|
1432 | else |
---|
1433 | vindex = integer_zero_node; |
---|
1434 | if (DECL_CONTEXT (decl) |
---|
1435 | && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') |
---|
1436 | vcontext = build_t_desc (DECL_CONTEXT (decl), 0); |
---|
1437 | else |
---|
1438 | vcontext = integer_zero_node; |
---|
1439 | name_string = DECL_NAME (decl); |
---|
1440 | if (name_string == NULL) |
---|
1441 | name_string = DECL_ASSEMBLER_NAME (decl); |
---|
1442 | name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); |
---|
1443 | |
---|
1444 | /* Now decide whether the return type of this mvar |
---|
1445 | should cause it's type to get def'd or ref'd in this file. |
---|
1446 | If the type we are looking at has a proxy definition, |
---|
1447 | we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */ |
---|
1448 | taggr = TREE_TYPE (TREE_TYPE (decl)); |
---|
1449 | |
---|
1450 | if ((TREE_CODE (taggr) == POINTER_TYPE |
---|
1451 | || TREE_CODE (taggr) == REFERENCE_TYPE) |
---|
1452 | && TYPE_VOLATILE (taggr) == 0) |
---|
1453 | taggr = TREE_TYPE (taggr); |
---|
1454 | |
---|
1455 | elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), |
---|
1456 | tree_cons (NULL_TREE, vindex, |
---|
1457 | tree_cons (NULL_TREE, vcontext, |
---|
1458 | tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)), |
---|
1459 | ! IS_AGGR_TYPE (taggr)), |
---|
1460 | tree_cons (NULL_TREE, build_c_cast (build_pointer_type (default_function_type), build_unary_op (ADDR_EXPR, decl, 0), 0), |
---|
1461 | tree_cons (NULL_TREE, parm_count, |
---|
1462 | tree_cons (NULL_TREE, req_count, |
---|
1463 | build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0))))))))); |
---|
1464 | |
---|
1465 | taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems); |
---|
1466 | TREE_CONSTANT (taggr) = 1; |
---|
1467 | TREE_STATIC (taggr) = 1; |
---|
1468 | TREE_READONLY (taggr) = 1; |
---|
1469 | return taggr; |
---|
1470 | } |
---|
1471 | #endif /* dossier */ |
---|
1472 | |
---|
1473 | |
---|
1474 | /* Conditionally emit code to set up an unwind-protect for the |
---|
1475 | garbage collector. If this function doesn't do anything that involves |
---|
1476 | the garbage collector, then do nothing. Otherwise, call __gc_push |
---|
1477 | at the beginning and __gc_pop at the end. |
---|
1478 | |
---|
1479 | NOTE! The __gc_pop function must operate transparently, since |
---|
1480 | it comes where the logical return label lies. This means that |
---|
1481 | at runtime *it* must preserve any return value registers. */ |
---|
1482 | |
---|
1483 | void |
---|
1484 | expand_gc_prologue_and_epilogue () |
---|
1485 | { |
---|
1486 | extern tree maybe_gc_cleanup; |
---|
1487 | struct rtx_def *last_parm_insn, *mark; |
---|
1488 | extern struct rtx_def *get_last_insn (); |
---|
1489 | extern struct rtx_def *get_first_nonparm_insn (); |
---|
1490 | extern struct rtx_def *previous_insn (); |
---|
1491 | tree action; |
---|
1492 | |
---|
1493 | /* If we didn't need the obstack, don't cons any space. */ |
---|
1494 | if (current_function_obstack_index == 0 |
---|
1495 | || current_function_obstack_usage == 0) |
---|
1496 | return; |
---|
1497 | |
---|
1498 | mark = get_last_insn (); |
---|
1499 | last_parm_insn = get_first_nonparm_insn (); |
---|
1500 | if (last_parm_insn == 0) last_parm_insn = mark; |
---|
1501 | else last_parm_insn = previous_insn (last_parm_insn); |
---|
1502 | |
---|
1503 | action = build_function_call (gc_push_fndecl, |
---|
1504 | build_tree_list (NULL_TREE, size_int (++current_function_obstack_index))); |
---|
1505 | expand_expr_stmt (action); |
---|
1506 | |
---|
1507 | reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn); |
---|
1508 | |
---|
1509 | /* This will be expanded as a cleanup. */ |
---|
1510 | TREE_VALUE (maybe_gc_cleanup) |
---|
1511 | = build_function_call (gc_pop_fndecl, NULL_TREE); |
---|
1512 | } |
---|
1513 | |
---|
1514 | /* Some day we'll use this function as a call-back and clean |
---|
1515 | up all the unnecessary gc dribble that we otherwise create. */ |
---|
1516 | void |
---|
1517 | lang_expand_end_bindings (first, last) |
---|
1518 | struct rtx_def *first, *last; |
---|
1519 | { |
---|
1520 | } |
---|
1521 | |
---|
1522 | void |
---|
1523 | init_gc_processing () |
---|
1524 | { |
---|
1525 | tree parmtypes = hash_tree_chain (class_star_type_node, |
---|
1526 | hash_tree_chain (integer_type_node, NULL_TREE)); |
---|
1527 | gc_protect_fndecl = define_function ("__gc_protect", |
---|
1528 | build_function_type (class_star_type_node, parmtypes), |
---|
1529 | NOT_BUILT_IN, 0, 0); |
---|
1530 | |
---|
1531 | parmtypes = hash_tree_chain (integer_type_node, NULL_TREE); |
---|
1532 | gc_unprotect_fndecl = define_function ("__gc_unprotect", |
---|
1533 | build_function_type (void_type_node, parmtypes), |
---|
1534 | NOT_BUILT_IN, 0, 0); |
---|
1535 | |
---|
1536 | gc_push_fndecl = define_function ("__gc_push", |
---|
1537 | TREE_TYPE (gc_unprotect_fndecl), |
---|
1538 | NOT_BUILT_IN, 0, 0); |
---|
1539 | |
---|
1540 | gc_pop_fndecl = define_function ("__gc_pop", |
---|
1541 | build_function_type (void_type_node, |
---|
1542 | void_list_node), |
---|
1543 | NOT_BUILT_IN, 0, 0); |
---|
1544 | gc_nonobject = build_int_2 (0x80000000, 0); |
---|
1545 | gc_visible = build_int_2 (0x40000000, 0); |
---|
1546 | gc_white = integer_zero_node; |
---|
1547 | gc_offwhite = build_int_2 (0x10000000, 0); |
---|
1548 | gc_grey = build_int_2 (0x20000000, 0); |
---|
1549 | gc_black = build_int_2 (0x30000000, 0); |
---|
1550 | } |
---|