]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/except.c
tree.c (avoid_overlap): Add prototype.
[gcc.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann <tiemann@cygnus.com>
4 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5 initial re-implementation courtesy Tad Hunt.
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24
25 #include "config.h"
26 #include "system.h"
27 #include "tree.h"
28 #include "rtl.h"
29 #include "cp-tree.h"
30 #include "flags.h"
31 #include "obstack.h"
32 #include "expr.h"
33 #include "output.h"
34 #include "except.h"
35 #include "function.h"
36 #include "defaults.h"
37
38 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
39
40 /* Holds the fndecl for __builtin_return_address. */
41 tree builtin_return_address_fndecl;
42
43 /* A couple of backend routines from m88k.c */
44
45 static void push_eh_cleanup PROTO((void));
46 static rtx do_function_call PROTO((tree, tree, tree));
47 static tree build_eh_type_type PROTO((tree));
48 static tree build_eh_type PROTO((tree));
49 static void expand_end_eh_spec PROTO((tree));
50 static tree call_eh_info PROTO((void));
51 static void push_eh_info PROTO((void));
52 static tree get_eh_info PROTO((void));
53 static tree get_eh_value PROTO((void));
54 static tree get_eh_type PROTO((void));
55 static tree get_eh_caught PROTO((void));
56 static tree get_eh_handlers PROTO((void));
57 static tree do_pop_exception PROTO((void));
58
59 #if 0
60 /* This is the startup, and finish stuff per exception table. */
61
62 /* XXX - Tad: exception handling section */
63 #ifndef EXCEPT_SECTION_ASM_OP
64 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
65 #endif
66
67 #ifdef EXCEPT_SECTION_ASM_OP
68 typedef struct {
69 void *start_region;
70 void *end_region;
71 void *exception_handler;
72 } exception_table;
73 #endif /* EXCEPT_SECTION_ASM_OP */
74
75 #ifdef EXCEPT_SECTION_ASM_OP
76
77 /* on machines which support it, the exception table lives in another section,
78 but it needs a label so we can reference it... This sets up that
79 label! */
80 asm (EXCEPT_SECTION_ASM_OP);
81 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
82 asm (TEXT_SECTION_ASM_OP);
83
84 #endif /* EXCEPT_SECTION_ASM_OP */
85
86 #ifdef EXCEPT_SECTION_ASM_OP
87
88 /* we need to know where the end of the exception table is... so this
89 is how we do it! */
90
91 asm (EXCEPT_SECTION_ASM_OP);
92 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
93 asm (TEXT_SECTION_ASM_OP);
94
95 #endif /* EXCEPT_SECTION_ASM_OP */
96
97 #endif
98
99 #include "decl.h"
100 #include "insn-flags.h"
101 #include "obstack.h"
102
103 /* ======================================================================
104 Briefly the algorithm works like this:
105
106 When a constructor or start of a try block is encountered,
107 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
108 new entry in the unwind protection stack and returns a label to
109 output to start the protection for that block.
110
111 When a destructor or end try block is encountered, pop_eh_entry
112 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
113 created when push_eh_entry () was called. The eh_entry structure
114 contains three things at this point. The start protect label,
115 the end protect label, and the exception handler label. The end
116 protect label should be output before the call to the destructor
117 (if any). If it was a destructor, then its parse tree is stored
118 in the finalization variable in the eh_entry structure. Otherwise
119 the finalization variable is set to NULL to reflect the fact that
120 is the the end of a try block. Next, this modified eh_entry node
121 is enqueued in the finalizations queue by calling
122 enqueue_eh_entry (&queue,entry).
123
124 +---------------------------------------------------------------+
125 |XXX: Will need modification to deal with partially |
126 | constructed arrays of objects |
127 | |
128 | Basically, this consists of keeping track of how many |
129 | of the objects have been constructed already (this |
130 | should be in a register though, so that shouldn't be a |
131 | problem. |
132 +---------------------------------------------------------------+
133
134 When a catch block is encountered, there is a lot of work to be
135 done.
136
137 Since we don't want to generate the catch block inline with the
138 regular flow of the function, we need to have some way of doing
139 so. Luckily, we can use sequences to defer the catch sections.
140 When the start of a catch block is encountered, we start the
141 sequence. After the catch block is generated, we end the
142 sequence.
143
144 Next we must insure that when the catch block is executed, all
145 finalizations for the matching try block have been completed. If
146 any of those finalizations throw an exception, we must call
147 terminate according to the ARM (section r.15.6.1). What this
148 means is that we need to dequeue and emit finalizations for each
149 entry in the eh_queue until we get to an entry with a NULL
150 finalization field. For any of the finalization entries, if it
151 is not a call to terminate (), we must protect it by giving it
152 another start label, end label, and exception handler label,
153 setting its finalization tree to be a call to terminate (), and
154 enqueue'ing this new eh_entry to be output at an outer level.
155 Finally, after all that is done, we can get around to outputting
156 the catch block which basically wraps all the "catch (...) {...}"
157 statements in a big if/then/else construct that matches the
158 correct block to call.
159
160 ===================================================================== */
161
162 /* local globals for function calls
163 ====================================================================== */
164
165 /* Used to cache "terminate" and "__throw_type_match*". */
166 static tree Terminate, CatchMatch;
167
168 /* Used to cache __find_first_exception_table_match for throw. */
169 static tree FirstExceptionMatch;
170
171 /* Used to cache a call to __unwind_function. */
172 static tree Unwind;
173
174 /* ====================================================================== */
175
176
177 /* ========================================================================= */
178
179
180
181 /* local globals - these local globals are for storing data necessary for
182 generating the exception table and code in the correct order.
183
184 ========================================================================= */
185
186 extern rtx catch_clauses;
187 extern tree const_ptr_type_node;
188
189 /* ========================================================================= */
190
191 /* Cheesyness to save some typing. Returns the return value rtx. */
192
193 static rtx
194 do_function_call (func, params, return_type)
195 tree func, params, return_type;
196 {
197 tree func_call;
198 func_call = build_function_call (func, params);
199 expand_call (func_call, NULL_RTX, 0);
200 if (return_type != NULL_TREE)
201 return hard_function_value (return_type, func_call);
202 return NULL_RTX;
203 }
204
205 /* ========================================================================= */
206
207 /* sets up all the global eh stuff that needs to be initialized at the
208 start of compilation.
209
210 This includes:
211 - Setting up all the function call trees. */
212
213 void
214 init_exception_processing ()
215 {
216 /* void vtype () */
217 tree vtype = build_function_type (void_type_node, void_list_node);
218
219 Terminate = auto_function (get_identifier ("terminate"),
220 vtype, NOT_BUILT_IN);
221 TREE_THIS_VOLATILE (Terminate) = 1;
222
223 push_lang_context (lang_name_c);
224
225 CatchMatch
226 = builtin_function (flag_rtti
227 ? "__throw_type_match_rtti"
228 : "__throw_type_match",
229 build_function_type (ptr_type_node,
230 tree_cons (NULL_TREE, const_ptr_type_node,
231 tree_cons (NULL_TREE, const_ptr_type_node,
232 tree_cons (NULL_TREE, ptr_type_node,
233 void_list_node)))),
234 NOT_BUILT_IN, NULL_PTR);
235 FirstExceptionMatch
236 = builtin_function ("__find_first_exception_table_match",
237 build_function_type (ptr_type_node,
238 tree_cons (NULL_TREE, ptr_type_node,
239 void_list_node)),
240 NOT_BUILT_IN, NULL_PTR);
241 Unwind
242 = builtin_function ("__unwind_function",
243 build_function_type (void_type_node,
244 tree_cons (NULL_TREE, ptr_type_node,
245 void_list_node)),
246 NOT_BUILT_IN, NULL_PTR);
247
248 pop_lang_context ();
249
250 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
251 be protected with __terminate. */
252 protect_cleanup_actions_with_terminate = 1;
253 }
254
255 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
256
257 static tree
258 call_eh_info ()
259 {
260 tree fn;
261
262 fn = get_identifier ("__cp_exception_info");
263 if (IDENTIFIER_GLOBAL_VALUE (fn))
264 fn = IDENTIFIER_GLOBAL_VALUE (fn);
265 else
266 {
267 tree t, fields[6];
268
269 /* Declare cp_eh_info * __cp_exception_info (void),
270 as defined in exception.cc. */
271 push_obstacks_nochange ();
272 end_temporary_allocation ();
273
274 /* struct cp_eh_info. This must match exception.cc. Note that this
275 type is not pushed anywhere. */
276 t = make_lang_type (RECORD_TYPE);
277 fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
278 ptr_type_node);
279 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
280 ptr_type_node);
281 fields[2] = build_lang_field_decl
282 (FIELD_DECL, get_identifier ("cleanup"),
283 build_pointer_type (build_function_type
284 (ptr_type_node, tree_cons
285 (NULL_TREE, ptr_type_node, void_list_node))));
286 fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
287 boolean_type_node);
288 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
289 build_pointer_type (t));
290 fields[5] = build_lang_field_decl
291 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
292 /* N.B.: The fourth field LEN is expected to be
293 the number of fields - 1, not the total number of fields. */
294 finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
295 t = build_pointer_type (t);
296
297 /* And now the function. */
298 fn = build_lang_decl (FUNCTION_DECL, fn,
299 build_function_type (t, void_list_node));
300 DECL_EXTERNAL (fn) = 1;
301 TREE_PUBLIC (fn) = 1;
302 DECL_ARTIFICIAL (fn) = 1;
303 pushdecl_top_level (fn);
304 make_function_rtl (fn);
305 assemble_external (fn);
306 pop_obstacks ();
307 }
308 return build_function_call (fn, NULL_TREE);
309 }
310
311 /* Retrieve a pointer to the cp_eh_info node for the current exception
312 and save it in the current binding level. */
313
314 static void
315 push_eh_info ()
316 {
317 tree decl, fn = call_eh_info ();
318
319 /* Remember the pointer to the current exception info; it won't change
320 during this catch block. */
321 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
322 TREE_TYPE (fn));
323 DECL_ARTIFICIAL (decl) = 1;
324 DECL_INITIAL (decl) = fn;
325 decl = pushdecl (decl);
326 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
327 }
328
329 /* Returns a reference to the cp_eh_info node for the current exception. */
330
331 static tree
332 get_eh_info ()
333 {
334 /* Look for the pointer pushed in push_eh_info. */
335 tree t = lookup_name (get_identifier ("__exception_info"), 0);
336 return build_indirect_ref (t, NULL_PTR);
337 }
338
339 /* Returns a reference to the current exception object. */
340
341 static tree
342 get_eh_value ()
343 {
344 return build_component_ref (get_eh_info (), get_identifier ("value"),
345 NULL_TREE, 0);
346 }
347
348 /* Returns a reference to the current exception type. */
349
350 static tree
351 get_eh_type ()
352 {
353 return build_component_ref (get_eh_info (), get_identifier ("type"),
354 NULL_TREE, 0);
355 }
356
357 /* Returns a reference to whether or not the current exception
358 has been caught. */
359
360 static tree
361 get_eh_caught ()
362 {
363 return build_component_ref (get_eh_info (), get_identifier ("caught"),
364 NULL_TREE, 0);
365 }
366
367 /* Returns a reference to whether or not the current exception
368 has been caught. */
369
370 static tree
371 get_eh_handlers ()
372 {
373 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
374 NULL_TREE, 0);
375 }
376
377 /* Build a type value for use at runtime for a type that is matched
378 against by the exception handling system. */
379
380 static tree
381 build_eh_type_type (type)
382 tree type;
383 {
384 char *typestring;
385 tree exp;
386
387 if (type == error_mark_node)
388 return error_mark_node;
389
390 /* peel back references, so they match. */
391 if (TREE_CODE (type) == REFERENCE_TYPE)
392 type = TREE_TYPE (type);
393
394 /* Peel off cv qualifiers. */
395 type = TYPE_MAIN_VARIANT (type);
396
397 if (flag_rtti)
398 {
399 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
400 }
401
402 typestring = build_overload_name (type, 1, 1);
403 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
404 return build1 (ADDR_EXPR, ptr_type_node, exp);
405 }
406
407 /* Build a type value for use at runtime for a exp that is thrown or
408 matched against by the exception handling system. */
409
410 static tree
411 build_eh_type (exp)
412 tree exp;
413 {
414 if (flag_rtti)
415 {
416 exp = build_typeid (exp);
417 return build1 (ADDR_EXPR, ptr_type_node, exp);
418 }
419 return build_eh_type_type (TREE_TYPE (exp));
420 }
421
422 /* Build up a call to __cp_pop_exception, to destroy the exception object
423 for the current catch block. HANDLER is either true or false, telling
424 the library whether or not it is being called from an exception handler;
425 if it is, it avoids destroying the object on rethrow. */
426
427 static tree
428 do_pop_exception ()
429 {
430 tree fn, cleanup;
431 fn = get_identifier ("__cp_pop_exception");
432 if (IDENTIFIER_GLOBAL_VALUE (fn))
433 fn = IDENTIFIER_GLOBAL_VALUE (fn);
434 else
435 {
436 /* Declare void __cp_pop_exception (void *),
437 as defined in exception.cc. */
438 push_obstacks_nochange ();
439 end_temporary_allocation ();
440 fn = build_lang_decl
441 (FUNCTION_DECL, fn,
442 build_function_type (void_type_node, tree_cons
443 (NULL_TREE, ptr_type_node, void_list_node)));
444 DECL_EXTERNAL (fn) = 1;
445 TREE_PUBLIC (fn) = 1;
446 DECL_ARTIFICIAL (fn) = 1;
447 pushdecl_top_level (fn);
448 make_function_rtl (fn);
449 assemble_external (fn);
450 pop_obstacks ();
451 }
452
453 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
454 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
455 cleanup = build_function_call (fn, expr_tree_cons
456 (NULL_TREE, cleanup, NULL_TREE));
457 return cleanup;
458 }
459
460 /* This routine creates the cleanup for the current exception. */
461
462 static void
463 push_eh_cleanup ()
464 {
465 int yes;
466
467 expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
468 const0_rtx, VOIDmode, EXPAND_NORMAL);
469
470 yes = suspend_momentary ();
471 /* All cleanups must last longer than normal. */
472 expand_decl_cleanup (NULL_TREE, do_pop_exception ());
473 resume_momentary (yes);
474 }
475
476 /* Build up a call to terminate on the function obstack, for use as an
477 exception handler. */
478
479 tree
480 build_terminate_handler ()
481 {
482 int yes = suspend_momentary ();
483 tree term = build_function_call (Terminate, NULL_TREE);
484 resume_momentary (yes);
485 return term;
486 }
487
488 /* call this to start a catch block. Typename is the typename, and identifier
489 is the variable to place the object in or NULL if the variable doesn't
490 matter. If typename is NULL, that means its a "catch (...)" or catch
491 everything. In that case we don't need to do any type checking.
492 (ie: it ends up as the "else" clause rather than an "else if" clause) */
493
494 void
495 expand_start_catch_block (declspecs, declarator)
496 tree declspecs, declarator;
497 {
498 rtx false_label_rtx;
499 tree decl = NULL_TREE;
500 tree init;
501
502 if (processing_template_decl)
503 {
504 if (declspecs)
505 {
506 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
507 1, NULL_TREE);
508 pushdecl (decl);
509 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
510 copy_to_permanent (declspecs),
511 NULL_TREE);
512 add_tree (decl);
513 }
514 return;
515 }
516
517 if (! doing_eh (1))
518 return;
519
520 /* Create a binding level for the eh_info and the exception object
521 cleanup. */
522 pushlevel (0);
523 expand_start_bindings (0);
524
525 false_label_rtx = gen_label_rtx ();
526 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
527
528 emit_line_note (input_filename, lineno);
529
530 push_eh_info ();
531
532 if (declspecs)
533 {
534 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
535
536 if (decl == NULL_TREE)
537 error ("invalid catch parameter");
538 }
539
540 if (decl)
541 {
542 tree exp;
543 rtx call_rtx, return_value_rtx;
544 tree init_type;
545
546 /* Make sure we mark the catch param as used, otherwise we'll get
547 a warning about an unused ((anonymous)). */
548 TREE_USED (decl) = 1;
549
550 /* Figure out the type that the initializer is. */
551 init_type = TREE_TYPE (decl);
552 if (TREE_CODE (init_type) != REFERENCE_TYPE
553 && TREE_CODE (init_type) != POINTER_TYPE)
554 init_type = build_reference_type (init_type);
555
556 exp = get_eh_value ();
557
558 /* Since pointers are passed by value, initialize a reference to
559 pointer catch parm with the address of the value slot. */
560 if (TREE_CODE (init_type) == REFERENCE_TYPE
561 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
562 exp = build_unary_op (ADDR_EXPR, exp, 1);
563
564 exp = expr_tree_cons (NULL_TREE,
565 build_eh_type_type (TREE_TYPE (decl)),
566 expr_tree_cons (NULL_TREE,
567 get_eh_type (),
568 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
569 exp = build_function_call (CatchMatch, exp);
570 call_rtx = expand_call (exp, NULL_RTX, 0);
571
572 return_value_rtx = hard_function_value (ptr_type_node, exp);
573
574 /* did the throw type match function return TRUE? */
575 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
576 GET_MODE (return_value_rtx), 0, 0);
577
578 /* if it returned FALSE, jump over the catch block, else fall into it */
579 emit_jump_insn (gen_beq (false_label_rtx));
580
581 push_eh_cleanup ();
582
583 /* Create a binding level for the parm. */
584 pushlevel (0);
585 expand_start_bindings (0);
586
587 init = convert_from_reference (make_tree (init_type, call_rtx));
588
589 /* If the constructor for the catch parm exits via an exception, we
590 must call terminate. See eh23.C. */
591 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
592 {
593 /* Generate the copy constructor call directly so we can wrap it.
594 See also expand_default_init. */
595 init = ocp_convert (TREE_TYPE (decl), init,
596 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
597 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
598 build_terminate_handler ());
599 }
600
601 /* Let `cp_finish_decl' know that this initializer is ok. */
602 DECL_INITIAL (decl) = init;
603 decl = pushdecl (decl);
604
605 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
606 }
607 else
608 {
609 push_eh_cleanup ();
610
611 /* Create a binding level for the parm. */
612 pushlevel (0);
613 expand_start_bindings (0);
614
615 /* Fall into the catch all section. */
616 }
617
618 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
619 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
620
621 emit_line_note (input_filename, lineno);
622 }
623
624
625
626 /* Call this to end a catch block. Its responsible for emitting the
627 code to handle jumping back to the correct place, and for emitting
628 the label to jump to if this catch block didn't match. */
629
630 void
631 expand_end_catch_block ()
632 {
633 if (! doing_eh (1))
634 return;
635
636 /* Cleanup the EH parameter. */
637 expand_end_bindings (getdecls (), kept_level_p (), 0);
638 poplevel (kept_level_p (), 1, 0);
639
640 /* Cleanup the EH object. */
641 expand_end_bindings (getdecls (), kept_level_p (), 0);
642 poplevel (kept_level_p (), 1, 0);
643
644 /* Fall to outside the try statement when done executing handler and
645 we fall off end of handler. This is jump Lresume in the
646 documentation. */
647 expand_goto (top_label_entry (&caught_return_label_stack));
648
649 /* label we emit to jump to if this catch block didn't match. */
650 /* This the closing } in the `if (eq) {' of the documentation. */
651 emit_label (pop_label_entry (&false_label_stack));
652 }
653
654 /* An exception spec is implemented more or less like:
655
656 try {
657 function body;
658 } catch (...) {
659 void *p[] = { typeid(raises) };
660 __check_eh_spec (p, count);
661 }
662
663 __check_eh_spec in exception.cc handles all the details. */
664
665 void
666 expand_start_eh_spec ()
667 {
668 expand_start_try_stmts ();
669 }
670
671 static void
672 expand_end_eh_spec (raises)
673 tree raises;
674 {
675 tree tmp, fn, decl, types = NULL_TREE;
676 int count = 0;
677
678 expand_start_all_catch ();
679 expand_start_catch_block (NULL_TREE, NULL_TREE);
680
681 /* Build up an array of type_infos. */
682 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
683 {
684 types = expr_tree_cons
685 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
686 ++count;
687 }
688
689 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
690 TREE_HAS_CONSTRUCTOR (types) = 1;
691
692 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
693 tmp = build_array_type (const_ptr_type_node, NULL_TREE);
694 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
695 DECL_ARTIFICIAL (decl) = 1;
696 DECL_INITIAL (decl) = types;
697 cp_finish_decl (decl, types, NULL_TREE, 0, 0);
698
699 decl = decay_conversion (decl);
700
701 fn = get_identifier ("__check_eh_spec");
702 if (IDENTIFIER_GLOBAL_VALUE (fn))
703 fn = IDENTIFIER_GLOBAL_VALUE (fn);
704 else
705 {
706 push_obstacks_nochange ();
707 end_temporary_allocation ();
708
709 tmp = tree_cons
710 (NULL_TREE, integer_type_node, tree_cons
711 (NULL_TREE, TREE_TYPE (decl), void_list_node));
712 tmp = build_function_type (void_type_node, tmp);
713
714 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
715 DECL_EXTERNAL (fn) = 1;
716 TREE_PUBLIC (fn) = 1;
717 DECL_ARTIFICIAL (fn) = 1;
718 TREE_THIS_VOLATILE (fn) = 1;
719 pushdecl_top_level (fn);
720 make_function_rtl (fn);
721 assemble_external (fn);
722 pop_obstacks ();
723 }
724
725 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
726 (NULL_TREE, decl, NULL_TREE));
727 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
728 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
729
730 expand_end_catch_block ();
731 expand_end_all_catch ();
732 }
733
734 /* This is called to expand all the toplevel exception handling
735 finalization for a function. It should only be called once per
736 function. */
737
738 void
739 expand_exception_blocks ()
740 {
741 do_pending_stack_adjust ();
742 push_to_sequence (catch_clauses);
743 expand_leftover_cleanups ();
744 do_pending_stack_adjust ();
745 catch_clauses = get_insns ();
746 end_sequence ();
747
748 /* Do this after we expand leftover cleanups, so that the
749 expand_eh_region_end that expand_end_eh_spec does will match the
750 right expand_eh_region_start, and make sure it comes out before
751 the terminate protected region. */
752 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
753 {
754 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
755 do_pending_stack_adjust ();
756 push_to_sequence (catch_clauses);
757 expand_leftover_cleanups ();
758 do_pending_stack_adjust ();
759 catch_clauses = get_insns ();
760 end_sequence ();
761 }
762
763 if (catch_clauses)
764 {
765 rtx funcend = gen_label_rtx ();
766 emit_jump (funcend);
767
768 /* We cannot protect n regions this way if we must flow into the
769 EH region through the top of the region, as we have to with
770 the setjmp/longjmp approach. */
771 if (exceptions_via_longjmp == 0)
772 expand_eh_region_start ();
773
774 emit_insns (catch_clauses);
775 catch_clauses = NULL_RTX;
776
777 if (exceptions_via_longjmp == 0)
778 expand_eh_region_end (build_terminate_handler ());
779
780 expand_leftover_cleanups ();
781
782 emit_label (funcend);
783 }
784 }
785
786 tree
787 start_anon_func ()
788 {
789 static int counter = 0;
790 int old_interface_unknown = interface_unknown;
791 char name[32];
792 tree params;
793 tree t;
794
795 push_cp_function_context (NULL_TREE);
796 push_to_top_level ();
797
798 /* No need to mangle this. */
799 push_lang_context (lang_name_c);
800
801 interface_unknown = 1;
802
803 params = void_list_node;
804 /* tcf stands for throw clean function. */
805 sprintf (name, "__tcf_%d", counter++);
806 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
807 NULL_TREE);
808 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
809 void_list_node),
810 t, NULL_TREE, 0);
811 store_parm_decls ();
812 pushlevel (0);
813 clear_last_expr ();
814 push_momentary ();
815 expand_start_bindings (0);
816 emit_line_note (input_filename, lineno);
817
818 interface_unknown = old_interface_unknown;
819
820 pop_lang_context ();
821
822 return current_function_decl;
823 }
824
825 void
826 end_anon_func ()
827 {
828 expand_end_bindings (getdecls (), 1, 0);
829 poplevel (1, 0, 0);
830 pop_momentary ();
831
832 finish_function (lineno, 0, 0);
833
834 pop_from_top_level ();
835 pop_cp_function_context (NULL_TREE);
836 }
837
838 /* Return a pointer to a buffer for an exception object of type TYPE. */
839
840 tree
841 alloc_eh_object (type)
842 tree type;
843 {
844 tree fn, exp;
845
846 fn = get_identifier ("__eh_alloc");
847 if (IDENTIFIER_GLOBAL_VALUE (fn))
848 fn = IDENTIFIER_GLOBAL_VALUE (fn);
849 else
850 {
851 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
852 tree tmp;
853 push_obstacks_nochange ();
854 end_temporary_allocation ();
855 tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
856 fn = build_lang_decl (FUNCTION_DECL, fn,
857 build_function_type (ptr_type_node, 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);
863 assemble_external (fn);
864 pop_obstacks ();
865 }
866
867 exp = build_function_call (fn, expr_tree_cons
868 (NULL_TREE, size_in_bytes (type), NULL_TREE));
869 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
870 return exp;
871 }
872
873 /* Expand a throw statement. This follows the following
874 algorithm:
875
876 1. Allocate space to save the current PC onto the stack.
877 2. Generate and emit a label and save its address into the
878 newly allocated stack space since we can't save the pc directly.
879 3. If this is the first call to throw in this function:
880 generate a label for the throw block
881 4. jump to the throw block label. */
882
883 void
884 expand_throw (exp)
885 tree exp;
886 {
887 tree fn;
888 static tree cleanup_type;
889
890 if (! doing_eh (1))
891 return;
892
893 if (exp)
894 {
895 tree throw_type;
896 tree cleanup = NULL_TREE, e;
897
898 /* throw expression */
899 /* First, decay it. */
900 exp = decay_conversion (exp);
901
902 /* cleanup_type is void (*)(void *, int),
903 the internal type of a destructor. */
904 if (cleanup_type == NULL_TREE)
905 {
906 push_obstacks_nochange ();
907 end_temporary_allocation ();
908 cleanup_type = build_pointer_type
909 (build_function_type
910 (void_type_node, tree_cons
911 (NULL_TREE, ptr_type_node, tree_cons
912 (NULL_TREE, integer_type_node, void_list_node))));
913 pop_obstacks ();
914 }
915
916 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
917 {
918 throw_type = build_eh_type (exp);
919 exp = build_reinterpret_cast (ptr_type_node, exp);
920 }
921 else
922 {
923 tree object, ptr;
924
925 /* OK, this is kind of wacky. The WP says that we call
926 terminate
927
928 when the exception handling mechanism, after completing
929 evaluation of the expression to be thrown but before the
930 exception is caught (_except.throw_), calls a user function
931 that exits via an uncaught exception.
932
933 So we have to protect the actual initialization of the
934 exception object with terminate(), but evaluate the expression
935 first. We also expand the call to __eh_alloc
936 first. Since there could be temps in the expression, we need
937 to handle that, too. */
938
939 expand_start_target_temps ();
940
941 #if 0
942 /* Unfortunately, this doesn't work. */
943 preexpand_calls (exp);
944 #else
945 /* Store the throw expression into a temp. This can be less
946 efficient than storing it into the allocated space directly, but
947 oh well. To do this efficiently we would need to insinuate
948 ourselves into expand_call. */
949 if (TREE_SIDE_EFFECTS (exp))
950 {
951 tree temp = build (VAR_DECL, TREE_TYPE (exp));
952 DECL_ARTIFICIAL (temp) = 1;
953 layout_decl (temp, 0);
954 DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
955 expand_expr (build (INIT_EXPR, TREE_TYPE (exp), temp, exp),
956 NULL_RTX, VOIDmode, 0);
957 expand_decl_cleanup (NULL_TREE, maybe_build_cleanup (temp));
958 exp = temp;
959 }
960 #endif
961
962 /* Allocate the space for the exception. */
963 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
964 expand_expr (ptr, const0_rtx, VOIDmode, 0);
965
966 expand_eh_region_start ();
967
968 object = build_indirect_ref (ptr, NULL_PTR);
969 exp = build_modify_expr (object, INIT_EXPR, exp);
970
971 if (exp == error_mark_node)
972 error (" in thrown expression");
973
974 expand_expr (exp, const0_rtx, VOIDmode, 0);
975 expand_eh_region_end (build_terminate_handler ());
976 expand_end_target_temps ();
977
978 throw_type = build_eh_type (object);
979
980 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
981 {
982 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
983 dtor_identifier, 0);
984 cleanup = TREE_VALUE (cleanup);
985 mark_used (cleanup);
986 mark_addressable (cleanup);
987 /* Pretend it's a normal function. */
988 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
989 }
990
991 exp = ptr;
992 }
993
994 if (cleanup == NULL_TREE)
995 {
996 cleanup = build_int_2 (0, 0);
997 TREE_TYPE (cleanup) = cleanup_type;
998 }
999
1000 fn = get_identifier ("__cp_push_exception");
1001 if (IDENTIFIER_GLOBAL_VALUE (fn))
1002 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1003 else
1004 {
1005 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1006 as defined in exception.cc. */
1007 tree tmp;
1008 push_obstacks_nochange ();
1009 end_temporary_allocation ();
1010 tmp = tree_cons
1011 (NULL_TREE, ptr_type_node, tree_cons
1012 (NULL_TREE, ptr_type_node, tree_cons
1013 (NULL_TREE, cleanup_type, void_list_node)));
1014 fn = build_lang_decl (FUNCTION_DECL, fn,
1015 build_function_type (void_type_node, tmp));
1016 DECL_EXTERNAL (fn) = 1;
1017 TREE_PUBLIC (fn) = 1;
1018 DECL_ARTIFICIAL (fn) = 1;
1019 pushdecl_top_level (fn);
1020 make_function_rtl (fn);
1021 assemble_external (fn);
1022 pop_obstacks ();
1023 }
1024
1025 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1026 (NULL_TREE, throw_type, expr_tree_cons
1027 (NULL_TREE, cleanup, NULL_TREE)));
1028 e = build_function_call (fn, e);
1029 expand_expr (e, const0_rtx, VOIDmode, 0);
1030 }
1031 else
1032 {
1033 /* rethrow current exception; note that it's no longer caught. */
1034
1035 tree fn = get_identifier ("__uncatch_exception");
1036 if (IDENTIFIER_GLOBAL_VALUE (fn))
1037 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1038 else
1039 {
1040 /* Declare void __uncatch_exception (void)
1041 as defined in exception.cc. */
1042 push_obstacks_nochange ();
1043 end_temporary_allocation ();
1044 fn = build_lang_decl (FUNCTION_DECL, fn,
1045 build_function_type (void_type_node,
1046 void_list_node));
1047 DECL_EXTERNAL (fn) = 1;
1048 TREE_PUBLIC (fn) = 1;
1049 DECL_ARTIFICIAL (fn) = 1;
1050 pushdecl_top_level (fn);
1051 make_function_rtl (fn);
1052 assemble_external (fn);
1053 pop_obstacks ();
1054 }
1055
1056 exp = build_function_call (fn, NULL_TREE);
1057 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1058 }
1059
1060 expand_internal_throw ();
1061 }
1062
1063 /* Build a throw expression. */
1064
1065 tree
1066 build_throw (e)
1067 tree e;
1068 {
1069 if (e != error_mark_node)
1070 {
1071 if (processing_template_decl)
1072 return build_min (THROW_EXPR, void_type_node, e);
1073 e = build1 (THROW_EXPR, void_type_node, e);
1074 TREE_SIDE_EFFECTS (e) = 1;
1075 TREE_USED (e) = 1;
1076 }
1077 return e;
1078 }
This page took 0.087772 seconds and 5 git commands to generate.