]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/except.c
bd26053dfcef3d343a828eb348d4b6db5ab6e40a
[gcc.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-95, 1996 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 <stdio.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 /* Used to cache a call to __builtin_return_address. */
46 static tree BuiltinReturnAddress;
47
48 static void easy_expand_asm PROTO((char *));
49 static void push_eh_cleanup PROTO((void));
50 static void do_unwind PROTO((rtx));
51 static rtx do_function_call PROTO((tree, tree, tree));
52 static tree build_eh_type_type PROTO((tree));
53 static tree build_eh_type PROTO((tree));
54 static void expand_end_eh_spec PROTO((tree));
55
56 static void
57 easy_expand_asm (str)
58 char *str;
59 {
60 expand_asm (build_string (strlen (str)+1, str));
61 }
62
63
64 #if 0
65 /* This is the startup, and finish stuff per exception table. */
66
67 /* XXX - Tad: exception handling section */
68 #ifndef EXCEPT_SECTION_ASM_OP
69 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
70 #endif
71
72 #ifdef EXCEPT_SECTION_ASM_OP
73 typedef struct {
74 void *start_region;
75 void *end_region;
76 void *exception_handler;
77 } exception_table;
78 #endif /* EXCEPT_SECTION_ASM_OP */
79
80 #ifdef EXCEPT_SECTION_ASM_OP
81
82 /* on machines which support it, the exception table lives in another section,
83 but it needs a label so we can reference it... This sets up that
84 label! */
85 asm (EXCEPT_SECTION_ASM_OP);
86 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
87 asm (TEXT_SECTION_ASM_OP);
88
89 #endif /* EXCEPT_SECTION_ASM_OP */
90
91 #ifdef EXCEPT_SECTION_ASM_OP
92
93 /* we need to know where the end of the exception table is... so this
94 is how we do it! */
95
96 asm (EXCEPT_SECTION_ASM_OP);
97 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
98 asm (TEXT_SECTION_ASM_OP);
99
100 #endif /* EXCEPT_SECTION_ASM_OP */
101
102 #endif
103
104 #include "decl.h"
105 #include "insn-flags.h"
106 #include "obstack.h"
107
108 /* ======================================================================
109 Briefly the algorithm works like this:
110
111 When a constructor or start of a try block is encountered,
112 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
113 new entry in the unwind protection stack and returns a label to
114 output to start the protection for that block.
115
116 When a destructor or end try block is encountered, pop_eh_entry
117 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
118 created when push_eh_entry () was called. The eh_entry structure
119 contains three things at this point. The start protect label,
120 the end protect label, and the exception handler label. The end
121 protect label should be output before the call to the destructor
122 (if any). If it was a destructor, then its parse tree is stored
123 in the finalization variable in the eh_entry structure. Otherwise
124 the finalization variable is set to NULL to reflect the fact that
125 is the the end of a try block. Next, this modified eh_entry node
126 is enqueued in the finalizations queue by calling
127 enqueue_eh_entry (&queue,entry).
128
129 +---------------------------------------------------------------+
130 |XXX: Will need modification to deal with partially |
131 | constructed arrays of objects |
132 | |
133 | Basically, this consists of keeping track of how many |
134 | of the objects have been constructed already (this |
135 | should be in a register though, so that shouldn't be a |
136 | problem. |
137 +---------------------------------------------------------------+
138
139 When a catch block is encountered, there is a lot of work to be
140 done.
141
142 Since we don't want to generate the catch block inline with the
143 regular flow of the function, we need to have some way of doing
144 so. Luckily, we can use sequences to defer the catch sections.
145 When the start of a catch block is encountered, we start the
146 sequence. After the catch block is generated, we end the
147 sequence.
148
149 Next we must insure that when the catch block is executed, all
150 finalizations for the matching try block have been completed. If
151 any of those finalizations throw an exception, we must call
152 terminate according to the ARM (section r.15.6.1). What this
153 means is that we need to dequeue and emit finalizations for each
154 entry in the eh_queue until we get to an entry with a NULL
155 finalization field. For any of the finalization entries, if it
156 is not a call to terminate (), we must protect it by giving it
157 another start label, end label, and exception handler label,
158 setting its finalization tree to be a call to terminate (), and
159 enqueue'ing this new eh_entry to be output at an outer level.
160 Finally, after all that is done, we can get around to outputting
161 the catch block which basically wraps all the "catch (...) {...}"
162 statements in a big if/then/else construct that matches the
163 correct block to call.
164
165 ===================================================================== */
166
167 /* local globals for function calls
168 ====================================================================== */
169
170 /* Used to cache "terminate", "unexpected", "set_terminate", and
171 "set_unexpected" after default_conversion. (lib-except.c) */
172 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
173
174 /* Used to cache __find_first_exception_table_match for throw. */
175 static tree FirstExceptionMatch;
176
177 /* Used to cache a call to __unwind_function. */
178 static tree Unwind;
179
180 /* Holds a ready to emit call to "terminate". */
181 static tree TerminateFunctionCall;
182
183 /* ====================================================================== */
184
185
186 /* ========================================================================= */
187
188
189
190 /* local globals - these local globals are for storing data necessary for
191 generating the exception table and code in the correct order.
192
193 ========================================================================= */
194
195 /* Holds the pc for doing "throw" */
196 static tree saved_pc;
197
198 extern int throw_used;
199 extern rtx catch_clauses;
200 extern tree const_ptr_type_node;
201
202 /* ========================================================================= */
203
204 /* Cheesyness to save some typing. Returns the return value rtx. */
205
206 static rtx
207 do_function_call (func, params, return_type)
208 tree func, params, return_type;
209 {
210 tree func_call;
211 func_call = build_function_call (func, params);
212 expand_call (func_call, NULL_RTX, 0);
213 if (return_type != NULL_TREE)
214 return hard_function_value (return_type, func_call);
215 return NULL_RTX;
216 }
217
218 /* ========================================================================= */
219
220 /* sets up all the global eh stuff that needs to be initialized at the
221 start of compilation.
222
223 This includes:
224 - Setting up all the function call trees. */
225
226 void
227 init_exception_processing ()
228 {
229 tree unexpected_fndecl, terminate_fndecl;
230 tree set_unexpected_fndecl, set_terminate_fndecl;
231 tree catch_match_fndecl;
232 tree find_first_exception_match_fndecl;
233 tree unwind_fndecl;
234 tree declspecs;
235 tree d;
236
237 /* void vtype () */
238 tree vtype = build_function_type (void_type_node, void_list_node);
239
240 /* void (*)() */
241 tree PFV = build_pointer_type (vtype);
242
243 /* Arg list for the build_function_type call for set_terminate and
244 set_unexpected. */
245 tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
246
247 /* void (*pfvtype (void (*) ()))() */
248 tree pfvtype = build_function_type (PFV, pfvlist);
249
250 set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
251 pfvtype, NOT_BUILT_IN);
252 set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
253 pfvtype, NOT_BUILT_IN);
254 unexpected_fndecl = auto_function (get_identifier ("unexpected"),
255 vtype, NOT_BUILT_IN);
256 terminate_fndecl = auto_function (get_identifier ("terminate"),
257 vtype, NOT_BUILT_IN);
258 TREE_THIS_VOLATILE (terminate_fndecl) = 1;
259
260 push_lang_context (lang_name_c);
261
262 catch_match_fndecl
263 = builtin_function (flag_rtti
264 ? "__throw_type_match_rtti"
265 : "__throw_type_match",
266 build_function_type (ptr_type_node,
267 tree_cons (NULL_TREE, const_ptr_type_node,
268 tree_cons (NULL_TREE, const_ptr_type_node,
269 tree_cons (NULL_TREE, ptr_type_node,
270 void_list_node)))),
271 NOT_BUILT_IN, NULL_PTR);
272 find_first_exception_match_fndecl
273 = builtin_function ("__find_first_exception_table_match",
274 build_function_type (ptr_type_node,
275 tree_cons (NULL_TREE, ptr_type_node,
276 void_list_node)),
277 NOT_BUILT_IN, NULL_PTR);
278 unwind_fndecl
279 = builtin_function ("__unwind_function",
280 build_function_type (void_type_node,
281 tree_cons (NULL_TREE, ptr_type_node,
282 void_list_node)),
283 NOT_BUILT_IN, NULL_PTR);
284
285 Unexpected = default_conversion (unexpected_fndecl);
286 Terminate = default_conversion (terminate_fndecl);
287 SetTerminate = default_conversion (set_terminate_fndecl);
288 SetUnexpected = default_conversion (set_unexpected_fndecl);
289 CatchMatch = default_conversion (catch_match_fndecl);
290 FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
291 Unwind = default_conversion (unwind_fndecl);
292 BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
293
294 TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
295
296 pop_lang_context ();
297
298 d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
299 TREE_PUBLIC (d) = 1;
300 DECL_EXTERNAL (d) = 1;
301 DECL_ARTIFICIAL (d) = 1;
302 cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
303 saved_pc = d;
304
305 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
306 be protected with __terminate. */
307 protect_cleanup_actions_with_terminate = 1;
308 }
309
310 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
311
312 static tree
313 call_eh_info ()
314 {
315 tree fn;
316
317 fn = get_identifier ("__cp_exception_info");
318 if (IDENTIFIER_GLOBAL_VALUE (fn))
319 fn = IDENTIFIER_GLOBAL_VALUE (fn);
320 else
321 {
322 tree t, fields[5];
323
324 /* Declare cp_eh_info * __cp_exception_info (void),
325 as defined in exception.cc. */
326 push_obstacks_nochange ();
327 end_temporary_allocation ();
328
329 /* struct cp_eh_info. This must match exception.cc. Note that this
330 type is not pushed anywhere. */
331 t = make_lang_type (RECORD_TYPE);
332 fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
333 ptr_type_node);
334 fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
335 ptr_type_node);
336 fields[2] = build_lang_field_decl
337 (FIELD_DECL, get_identifier ("cleanup"),
338 build_pointer_type (build_function_type
339 (ptr_type_node, tree_cons
340 (NULL_TREE, ptr_type_node, void_list_node))));
341 fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
342 boolean_type_node);
343 fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
344 build_pointer_type (t));
345 /* N.B.: The fourth field LEN is expected to be
346 the number of fields - 1, not the total number of fields. */
347 finish_builtin_type (t, "cp_eh_info", fields, 4, ptr_type_node);
348 t = build_pointer_type (t);
349
350 /* And now the function. */
351 fn = build_lang_decl (FUNCTION_DECL, fn,
352 build_function_type (t, void_list_node));
353 DECL_EXTERNAL (fn) = 1;
354 TREE_PUBLIC (fn) = 1;
355 DECL_ARTIFICIAL (fn) = 1;
356 pushdecl_top_level (fn);
357 make_function_rtl (fn);
358 assemble_external (fn);
359 pop_obstacks ();
360 }
361 return build_function_call (fn, NULL_TREE);
362 }
363
364 /* Retrieve a pointer to the cp_eh_info node for the current exception
365 and save it in the current binding level. */
366
367 static void
368 push_eh_info ()
369 {
370 tree decl, fn = call_eh_info ();
371
372 /* Remember the pointer to the current exception info; it won't change
373 during this catch block. */
374 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
375 TREE_TYPE (fn));
376 DECL_ARTIFICIAL (decl) = 1;
377 DECL_INITIAL (decl) = fn;
378 decl = pushdecl (decl);
379 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
380 }
381
382 /* Returns a reference to the cp_eh_info node for the current exception. */
383
384 static tree
385 get_eh_info ()
386 {
387 /* Look for the pointer pushed in push_eh_info. */
388 tree t = lookup_name (get_identifier ("__exception_info"), 0);
389 return build_indirect_ref (t, NULL_PTR);
390 }
391
392 /* Returns a reference to the current exception object. */
393
394 static tree
395 get_eh_value ()
396 {
397 return build_component_ref (get_eh_info (), get_identifier ("value"),
398 NULL_TREE, 0);
399 }
400
401 /* Returns a reference to the current exception type. */
402
403 static tree
404 get_eh_type ()
405 {
406 return build_component_ref (get_eh_info (), get_identifier ("type"),
407 NULL_TREE, 0);
408 }
409
410 /* Returns a reference to whether or not the current exception
411 has been caught. */
412
413 static tree
414 get_eh_caught ()
415 {
416 return build_component_ref (get_eh_info (), get_identifier ("caught"),
417 NULL_TREE, 0);
418 }
419
420 /* Build a type value for use at runtime for a type that is matched
421 against by the exception handling system. */
422
423 static tree
424 build_eh_type_type (type)
425 tree type;
426 {
427 char *typestring;
428 tree exp;
429
430 if (type == error_mark_node)
431 return error_mark_node;
432
433 /* peel back references, so they match. */
434 if (TREE_CODE (type) == REFERENCE_TYPE)
435 type = TREE_TYPE (type);
436
437 /* Peel off cv qualifiers. */
438 type = TYPE_MAIN_VARIANT (type);
439
440 if (flag_rtti)
441 {
442 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
443 }
444
445 typestring = build_overload_name (type, 1, 1);
446 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
447 return build1 (ADDR_EXPR, ptr_type_node, exp);
448 }
449
450 /* Build a type value for use at runtime for a exp that is thrown or
451 matched against by the exception handling system. */
452
453 static tree
454 build_eh_type (exp)
455 tree exp;
456 {
457 if (flag_rtti)
458 {
459 exp = build_typeid (exp);
460 return build1 (ADDR_EXPR, ptr_type_node, exp);
461 }
462 return build_eh_type_type (TREE_TYPE (exp));
463 }
464
465 /* Build up a call to __cp_pop_exception, to destroy the exception object
466 for the current catch block. HANDLER is either true or false, telling
467 the library whether or not it is being called from an exception handler;
468 if it is, it avoids destroying the object on rethrow. */
469
470 static tree
471 do_pop_exception (handler)
472 tree handler;
473 {
474 tree fn, cleanup;
475 fn = get_identifier ("__cp_pop_exception");
476 if (IDENTIFIER_GLOBAL_VALUE (fn))
477 fn = IDENTIFIER_GLOBAL_VALUE (fn);
478 else
479 {
480 /* Declare void __cp_pop_exception (void *),
481 as defined in exception.cc. */
482 push_obstacks_nochange ();
483 end_temporary_allocation ();
484 fn = build_lang_decl
485 (FUNCTION_DECL, fn,
486 build_function_type (void_type_node, tree_cons
487 (NULL_TREE, ptr_type_node, tree_cons
488 (NULL_TREE, boolean_type_node,
489 void_list_node))));
490 DECL_EXTERNAL (fn) = 1;
491 TREE_PUBLIC (fn) = 1;
492 DECL_ARTIFICIAL (fn) = 1;
493 pushdecl_top_level (fn);
494 make_function_rtl (fn);
495 assemble_external (fn);
496 pop_obstacks ();
497 }
498
499 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
500 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
501 cleanup = build_function_call (fn, expr_tree_cons
502 (NULL_TREE, cleanup, expr_tree_cons
503 (NULL_TREE, handler, NULL_TREE)));
504 return cleanup;
505 }
506
507 /* This routine creates the cleanup for the current exception. */
508
509 static void
510 push_eh_cleanup ()
511 {
512 /* All cleanups must last longer than normal. */
513 int yes = suspend_momentary ();
514 expand_decl_cleanup_no_eh (NULL_TREE, do_pop_exception (boolean_false_node));
515 resume_momentary (yes);
516
517 /* We don't destroy the exception object on rethrow, so we can't use
518 the normal cleanup mechanism for it. */
519 expand_eh_region_start ();
520 }
521
522 /* call this to start a catch block. Typename is the typename, and identifier
523 is the variable to place the object in or NULL if the variable doesn't
524 matter. If typename is NULL, that means its a "catch (...)" or catch
525 everything. In that case we don't need to do any type checking.
526 (ie: it ends up as the "else" clause rather than an "else if" clause) */
527
528 void
529 expand_start_catch_block (declspecs, declarator)
530 tree declspecs, declarator;
531 {
532 rtx false_label_rtx;
533 tree decl = NULL_TREE;
534 tree init;
535
536 if (processing_template_decl)
537 {
538 if (declspecs)
539 {
540 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
541 1, NULL_TREE);
542 pushdecl (decl);
543 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
544 copy_to_permanent (declspecs),
545 NULL_TREE);
546 add_tree (decl);
547 }
548 return;
549 }
550
551 if (! doing_eh (1))
552 return;
553
554 /* If we are not doing setjmp/longjmp EH, because we are reordered
555 out of line, we arrange to rethrow in the outer context so as to
556 skip through the terminate region we are nested in, should we
557 encounter an exception in the catch handler. We also need to do
558 this because we are not physically within the try block, if any,
559 that contains this catch block.
560
561 Matches the end in expand_end_catch_block. */
562 if (! exceptions_via_longjmp)
563 expand_eh_region_start ();
564
565 /* Create a binding level for the eh_info and the exception object
566 cleanup. */
567 pushlevel (0);
568 expand_start_bindings (0);
569
570 false_label_rtx = gen_label_rtx ();
571 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
572
573 emit_line_note (input_filename, lineno);
574
575 push_eh_info ();
576
577 if (declspecs)
578 {
579 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
580
581 if (decl == NULL_TREE)
582 error ("invalid catch parameter");
583 }
584
585 if (decl)
586 {
587 tree exp;
588 rtx call_rtx, return_value_rtx;
589 tree init_type;
590
591 /* Make sure we mark the catch param as used, otherwise we'll get
592 a warning about an unused ((anonymous)). */
593 TREE_USED (decl) = 1;
594
595 /* Figure out the type that the initializer is. */
596 init_type = TREE_TYPE (decl);
597 if (TREE_CODE (init_type) != REFERENCE_TYPE
598 && TREE_CODE (init_type) != POINTER_TYPE)
599 init_type = build_reference_type (init_type);
600
601 exp = get_eh_value ();
602 exp = expr_tree_cons (NULL_TREE,
603 build_eh_type_type (TREE_TYPE (decl)),
604 expr_tree_cons (NULL_TREE,
605 get_eh_type (),
606 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
607 exp = build_function_call (CatchMatch, exp);
608 call_rtx = expand_call (exp, NULL_RTX, 0);
609 assemble_external (TREE_OPERAND (CatchMatch, 0));
610
611 return_value_rtx = hard_function_value (ptr_type_node, exp);
612
613 /* did the throw type match function return TRUE? */
614 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
615 GET_MODE (return_value_rtx), 0, 0);
616
617 /* if it returned FALSE, jump over the catch block, else fall into it */
618 emit_jump_insn (gen_beq (false_label_rtx));
619
620 push_eh_cleanup ();
621
622 /* Create a binding level for the parm. */
623 pushlevel (0);
624 expand_start_bindings (0);
625
626 init = convert_from_reference (make_tree (init_type, call_rtx));
627
628 /* If the constructor for the catch parm exits via an exception, we
629 must call terminate. See eh23.C. */
630 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
631 {
632 /* Generate the copy constructor call directly so we can wrap it.
633 See also expand_default_init. */
634 init = ocp_convert (TREE_TYPE (decl), init,
635 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
636 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
637 TerminateFunctionCall);
638 }
639
640 /* Let `cp_finish_decl' know that this initializer is ok. */
641 DECL_INITIAL (decl) = init;
642 decl = pushdecl (decl);
643
644 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
645 }
646 else
647 {
648 push_eh_cleanup ();
649
650 /* Create a binding level for the parm. */
651 pushlevel (0);
652 expand_start_bindings (0);
653
654 /* Fall into the catch all section. */
655 }
656
657 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
658 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
659
660 emit_line_note (input_filename, lineno);
661 }
662
663
664
665 /* Call this to end a catch block. Its responsible for emitting the
666 code to handle jumping back to the correct place, and for emitting
667 the label to jump to if this catch block didn't match. */
668
669 void
670 expand_end_catch_block ()
671 {
672 if (! doing_eh (1))
673 return;
674
675 /* Cleanup the EH parameter. */
676 expand_end_bindings (getdecls (), kept_level_p (), 0);
677 poplevel (kept_level_p (), 1, 0);
678
679 /* Matches push_eh_cleanup. */
680 expand_eh_region_end (do_pop_exception (boolean_true_node));
681
682 /* Cleanup the EH object. */
683 expand_end_bindings (getdecls (), kept_level_p (), 0);
684 poplevel (kept_level_p (), 1, 0);
685
686 if (! exceptions_via_longjmp)
687 {
688 /* If we are not doing setjmp/longjmp EH, we need an extra
689 region around the whole catch block to skip through the
690 terminate region we are nested in. */
691
692 tree t = make_node (RTL_EXPR);
693 TREE_TYPE (t) = void_type_node;
694 RTL_EXPR_RTL (t) = const0_rtx;
695 TREE_SIDE_EFFECTS (t) = 1;
696 do_pending_stack_adjust ();
697 start_sequence_for_rtl_expr (t);
698
699 expand_internal_throw (outer_context_label_stack->u.rlabel);
700
701 do_pending_stack_adjust ();
702 RTL_EXPR_SEQUENCE (t) = get_insns ();
703 end_sequence ();
704
705 /* For the rethrow region. */
706 expand_eh_region_end (t);
707 }
708
709 /* Fall to outside the try statement when done executing handler and
710 we fall off end of handler. This is jump Lresume in the
711 documentation. */
712 expand_goto (top_label_entry (&caught_return_label_stack));
713
714 expand_leftover_cleanups ();
715
716 /* label we emit to jump to if this catch block didn't match. */
717 /* This the closing } in the `if (eq) {' of the documentation. */
718 emit_label (pop_label_entry (&false_label_stack));
719 }
720
721 /* unwind the stack. */
722
723 static void
724 do_unwind (inner_throw_label)
725 rtx inner_throw_label;
726 {
727 #if defined (SPARC_STACK_ALIGN) /* was sparc */
728 /* This doesn't work for the flat model sparc, nor does it need to
729 as the default unwinder is only used to unwind non-flat frames. */
730 tree fcall;
731 tree params;
732 rtx next_pc;
733 rtx temp;
734
735 /* Call to __builtin_return_address. */
736 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
737 fcall = build_function_call (BuiltinReturnAddress, params);
738 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
739 /* In the return, the new pc is pc+8, as the value coming in is
740 really the address of the call insn, not the next insn. */
741 temp = gen_reg_rtx (Pmode);
742 emit_move_insn (temp, inner_throw_label);
743 emit_move_insn (next_pc, plus_constant (temp, -8));
744 emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
745 easy_expand_asm ("ret");
746 easy_expand_asm ("restore");
747 emit_barrier ();
748 #endif
749 #if defined (ARM_FRAME_RTX) /* was __arm */
750 if (flag_omit_frame_pointer)
751 sorry ("this implementation of exception handling requires a frame pointer");
752
753 emit_move_insn (stack_pointer_rtx,
754 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
755 emit_move_insn (hard_frame_pointer_rtx,
756 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
757 #endif
758 #if defined (TARGET_88000) /* was m88k */
759 rtx temp_frame = frame_pointer_rtx;
760
761 temp_frame = memory_address (Pmode, temp_frame);
762 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
763
764 /* hopefully this will successfully pop the frame! */
765 emit_move_insn (frame_pointer_rtx, temp_frame);
766 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
767 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
768 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
769 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
770
771 #if 0
772 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
773 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
774
775 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
776
777 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
778 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
779 #endif
780 #endif
781 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
782 tree fcall;
783 tree params;
784 rtx next_pc;
785
786 #if 0
787 /* I would like to do this here, but the move below doesn't seem to work. */
788 /* Call to __builtin_return_address. */
789 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
790 fcall = build_function_call (BuiltinReturnAddress, params);
791 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
792
793 emit_move_insn (next_pc, inner_throw_label);
794 /* So, for now, just pass throw label to stack unwinder. */
795 #endif
796 params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node,
797 inner_throw_label), NULL_TREE);
798
799 do_function_call (Unwind, params, NULL_TREE);
800 assemble_external (TREE_OPERAND (Unwind, 0));
801 emit_barrier ();
802 #endif
803 }
804
805
806 /* Is called from expand_exception_blocks to generate the code in a function
807 to "throw" if anything in the function needs to perform a throw.
808
809 expands "throw" as the following pseudo code:
810
811 throw:
812 eh = find_first_exception_match (saved_pc);
813 if (!eh) goto gotta_rethrow_it;
814 goto eh;
815
816 gotta_rethrow_it:
817 saved_pc = __builtin_return_address (0);
818 pop_to_previous_level ();
819 goto throw; */
820
821 void
822 expand_builtin_throw ()
823 {
824 #ifndef DWARF2_UNWIND_INFO
825 tree fcall;
826 tree params;
827 rtx handler;
828 rtx saved_pcnthrow;
829 rtx next_pc;
830 rtx gotta_rethrow_it;
831 rtx gotta_call_terminate;
832 rtx after_unwind;
833 rtx top_of_loop;
834 tree t;
835 rtx x;
836
837 if (! doing_eh (0))
838 return;
839
840 if (! throw_used)
841 return;
842
843 params = void_list_node;
844 t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
845 NULL_TREE);
846 start_function (decl_tree_cons (NULL_TREE,
847 get_identifier ("void"),
848 decl_tree_cons (NULL_TREE,
849 get_identifier ("static"),
850 NULL_TREE)),
851 t, NULL_TREE, 0);
852 store_parm_decls ();
853 pushlevel (0);
854 clear_last_expr ();
855 push_momentary ();
856 expand_start_bindings (0);
857
858 gotta_rethrow_it = gen_label_rtx ();
859 gotta_call_terminate = gen_label_rtx ();
860
861 /* These two can be frontend specific. If wanted, they can go in
862 expand_throw. */
863 /* Do we have a valid object we are throwing? */
864 t = call_eh_info ();
865 emit_cmp_insn (expand_expr (t, NULL_RTX, Pmode, 0),
866 const0_rtx, EQ, NULL_RTX,
867 GET_MODE (DECL_RTL (t)), 0, 0);
868 emit_jump_insn (gen_beq (gotta_call_terminate));
869
870 /* search for an exception handler for the saved_pc */
871 handler = do_function_call (FirstExceptionMatch,
872 expr_tree_cons (NULL_TREE, saved_pc,
873 NULL_TREE),
874 ptr_type_node);
875 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
876
877 /* did we find one? */
878 emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
879 GET_MODE (handler), 0, 0);
880
881 /* if not, jump to gotta_rethrow_it */
882 emit_jump_insn (gen_beq (gotta_rethrow_it));
883
884 {
885 rtx ret_val, x;
886 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
887 0, hard_frame_pointer_rtx);
888
889 /* Set it up so that we continue at the handler. */
890 emit_move_insn (ret_val, handler);
891 #ifdef RETURN_ADDR_OFFSET
892 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
893 if (x != ret_val)
894 emit_move_insn (ret_val, x);
895 #endif
896
897 expand_null_return ();
898 }
899
900 top_of_loop = gen_label_rtx ();
901 emit_label (top_of_loop);
902
903 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
904 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
905 {
906 saved_pcnthrow = gen_reg_rtx (Pmode);
907 emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
908 NULL_TREE));
909 }
910 #endif
911
912 /* Call to __builtin_return_address. */
913 #if defined (ARM_FRAME_RTX) /* was __arm */
914 /* This should be moved into arm.h:RETURN_ADDR_RTX */
915 /* This replaces a 'call' to __builtin_return_address */
916 next_pc = gen_reg_rtx (Pmode);
917 emit_move_insn (next_pc,
918 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
919 #else
920 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
921 fcall = build_function_call (BuiltinReturnAddress, params);
922 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
923 #endif
924
925 /* Did __builtin_return_address return a valid address? */
926 emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
927 GET_MODE (next_pc), 0, 0);
928
929 emit_jump_insn (gen_beq (gotta_call_terminate));
930
931 next_pc = eh_outer_context (next_pc);
932
933 /* Yes it did. */
934 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
935 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
936 {
937 rtx x;
938
939 x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
940 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
941 next_pc);
942 #ifdef FUNCTION_OUTGOING_VALUE
943 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
944 validize_mem (gen_rtx (MEM, Pmode,
945 plus_constant (saved_pcnthrow,
946 GET_MODE_SIZE (Pmode)))));
947 emit_insn (gen_rtx (USE, VOIDmode,
948 FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
949 #endif
950 }
951 else
952 #endif
953 emit_move_insn (eh_saved_pc_rtx, next_pc);
954
955 after_unwind = gen_label_rtx ();
956 do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
957
958 emit_label (after_unwind);
959
960 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
961 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
962 {
963 t = build_function_type (void_type_node, void_list_node);
964 t = make_tree (build_pointer_type (t),
965 hard_function_value (ptr_type_node,
966 NULL_TREE));
967 t = build_function_call (t, NULL_TREE);
968 expand_expr (t, const0_rtx, VOIDmode, 0);
969 }
970 else
971 #endif
972 emit_throw ();
973
974 /* no it didn't --> therefore we need to call terminate */
975 emit_label (gotta_call_terminate);
976 do_function_call (Terminate, NULL_TREE, NULL_TREE);
977 assemble_external (TREE_OPERAND (Terminate, 0));
978
979 {
980 rtx ret_val, x;
981 /* code to deal with unwinding and looking for it again */
982 emit_label (gotta_rethrow_it);
983 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
984 0, hard_frame_pointer_rtx);
985
986 /* Set it up so that we continue inside, at the top of the loop. */
987 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
988 #ifdef RETURN_ADDR_OFFSET
989 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
990 if (x != ret_val)
991 emit_move_insn (ret_val, x);
992 #endif
993
994 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
995 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
996 {
997 rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
998 "__eh_pcnthrow"),
999 NULL_RTX, 1,
1000 Pmode, 0);
1001 /* This is to get a version of throw that will throw properly. */
1002 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
1003 plus_constant (x, GET_MODE_SIZE (Pmode)))),
1004 throw_libfunc);
1005 #ifdef FUNCTION_OUTGOING_VALUE
1006 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
1007 x);
1008 emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
1009 #endif
1010 }
1011 #endif
1012
1013 /* Fall into epilogue to unwind prologue. */
1014 }
1015
1016 expand_end_bindings (getdecls (), 1, 0);
1017 poplevel (1, 0, 0);
1018 pop_momentary ();
1019
1020 finish_function (lineno, 0, 0);
1021 #endif /* DWARF2_UNWIND_INFO */
1022 }
1023
1024 /* An exception spec is implemented more or less like:
1025
1026 try {
1027 function body;
1028 } catch (...) {
1029 void *p[] = { typeid(raises) };
1030 __check_eh_spec (p, count);
1031 }
1032
1033 __check_eh_spec in exception.cc handles all the details. */
1034
1035 void
1036 expand_start_eh_spec ()
1037 {
1038 expand_start_try_stmts ();
1039 }
1040
1041 static void
1042 expand_end_eh_spec (raises)
1043 tree raises;
1044 {
1045 tree tmp, fn, decl, types = NULL_TREE;
1046 int count = 0;
1047
1048 expand_start_all_catch ();
1049 expand_start_catch_block (NULL_TREE, NULL_TREE);
1050
1051 /* Build up an array of type_infos. */
1052 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
1053 {
1054 types = expr_tree_cons
1055 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
1056 ++count;
1057 }
1058
1059 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
1060 TREE_HAS_CONSTRUCTOR (types) = 1;
1061
1062 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
1063 tmp = build_array_type (const_ptr_type_node, NULL_TREE);
1064 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
1065 DECL_ARTIFICIAL (decl) = 1;
1066 DECL_INITIAL (decl) = types;
1067 cp_finish_decl (decl, types, NULL_TREE, 0, 0);
1068
1069 decl = decay_conversion (decl);
1070
1071 fn = get_identifier ("__check_eh_spec");
1072 if (IDENTIFIER_GLOBAL_VALUE (fn))
1073 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1074 else
1075 {
1076 push_obstacks_nochange ();
1077 end_temporary_allocation ();
1078
1079 tmp = tree_cons
1080 (NULL_TREE, integer_type_node, tree_cons
1081 (NULL_TREE, TREE_TYPE (decl), void_list_node));
1082 tmp = build_function_type (void_type_node, tmp);
1083
1084 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
1085 DECL_EXTERNAL (fn) = 1;
1086 TREE_PUBLIC (fn) = 1;
1087 DECL_ARTIFICIAL (fn) = 1;
1088 TREE_THIS_VOLATILE (fn) = 1;
1089 pushdecl_top_level (fn);
1090 make_function_rtl (fn);
1091 assemble_external (fn);
1092 pop_obstacks ();
1093 }
1094
1095 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
1096 (NULL_TREE, decl, NULL_TREE));
1097 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
1098 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1099
1100 expand_end_catch_block ();
1101 expand_end_all_catch ();
1102 }
1103
1104 /* This is called to expand all the toplevel exception handling
1105 finalization for a function. It should only be called once per
1106 function. */
1107
1108 void
1109 expand_exception_blocks ()
1110 {
1111 do_pending_stack_adjust ();
1112 push_to_sequence (catch_clauses);
1113 expand_leftover_cleanups ();
1114 do_pending_stack_adjust ();
1115 catch_clauses = get_insns ();
1116 end_sequence ();
1117
1118 /* Do this after we expand leftover cleanups, so that the
1119 expand_eh_region_end that expand_end_eh_spec does will match the
1120 right expand_eh_region_start, and make sure it comes out before
1121 the terminate protected region. */
1122 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1123 {
1124 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1125 do_pending_stack_adjust ();
1126 push_to_sequence (catch_clauses);
1127 expand_leftover_cleanups ();
1128 do_pending_stack_adjust ();
1129 catch_clauses = get_insns ();
1130 end_sequence ();
1131 }
1132
1133 if (catch_clauses)
1134 {
1135 rtx funcend = gen_label_rtx ();
1136 emit_jump (funcend);
1137
1138 /* We cannot protect n regions this way if we must flow into the
1139 EH region through the top of the region, as we have to with
1140 the setjmp/longjmp approach. */
1141 if (exceptions_via_longjmp == 0)
1142 {
1143 /* Is this necessary? */
1144 assemble_external (TREE_OPERAND (Terminate, 0));
1145
1146 expand_eh_region_start ();
1147 }
1148
1149 emit_insns (catch_clauses);
1150 catch_clauses = NULL_RTX;
1151
1152 if (exceptions_via_longjmp == 0)
1153 expand_eh_region_end (TerminateFunctionCall);
1154
1155 expand_leftover_cleanups ();
1156
1157 emit_label (funcend);
1158 }
1159 }
1160
1161 tree
1162 start_anon_func ()
1163 {
1164 static int counter = 0;
1165 int old_interface_unknown = interface_unknown;
1166 char name[32];
1167 tree params;
1168 tree t;
1169
1170 push_cp_function_context (NULL_TREE);
1171 push_to_top_level ();
1172
1173 /* No need to mangle this. */
1174 push_lang_context (lang_name_c);
1175
1176 interface_unknown = 1;
1177
1178 params = void_list_node;
1179 /* tcf stands for throw clean funciton. */
1180 sprintf (name, "__tcf_%d", counter++);
1181 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1182 NULL_TREE);
1183 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1184 void_list_node),
1185 t, NULL_TREE, 0);
1186 store_parm_decls ();
1187 pushlevel (0);
1188 clear_last_expr ();
1189 push_momentary ();
1190 expand_start_bindings (0);
1191 emit_line_note (input_filename, lineno);
1192
1193 interface_unknown = old_interface_unknown;
1194
1195 pop_lang_context ();
1196
1197 return current_function_decl;
1198 }
1199
1200 void
1201 end_anon_func ()
1202 {
1203 expand_end_bindings (getdecls (), 1, 0);
1204 poplevel (1, 0, 0);
1205 pop_momentary ();
1206
1207 finish_function (lineno, 0, 0);
1208
1209 pop_from_top_level ();
1210 pop_cp_function_context (NULL_TREE);
1211 }
1212
1213 /* Expand a throw statement. This follows the following
1214 algorithm:
1215
1216 1. Allocate space to save the current PC onto the stack.
1217 2. Generate and emit a label and save its address into the
1218 newly allocated stack space since we can't save the pc directly.
1219 3. If this is the first call to throw in this function:
1220 generate a label for the throw block
1221 4. jump to the throw block label. */
1222
1223 void
1224 expand_throw (exp)
1225 tree exp;
1226 {
1227 rtx label;
1228 tree fn;
1229 static tree cleanup_type;
1230
1231 if (! doing_eh (1))
1232 return;
1233
1234 if (exp)
1235 {
1236 tree throw_type;
1237 tree cleanup = NULL_TREE, e;
1238
1239 /* throw expression */
1240 /* First, decay it. */
1241 exp = decay_conversion (exp);
1242
1243 /* cleanup_type is void (*)(void *, int),
1244 the internal type of a destructor. */
1245 if (cleanup_type == NULL_TREE)
1246 {
1247 push_obstacks_nochange ();
1248 end_temporary_allocation ();
1249 cleanup_type = build_pointer_type
1250 (build_function_type
1251 (void_type_node, tree_cons
1252 (NULL_TREE, ptr_type_node, tree_cons
1253 (NULL_TREE, integer_type_node, void_list_node))));
1254 pop_obstacks ();
1255 }
1256
1257 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1258 {
1259 throw_type = build_eh_type (exp);
1260 exp = build_reinterpret_cast (ptr_type_node, exp);
1261 }
1262 else
1263 {
1264 tree object;
1265
1266 /* Make a copy of the thrown object. WP 15.1.5 */
1267 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1268 build_expr_list (NULL_TREE, exp),
1269 0);
1270
1271 if (exp == error_mark_node)
1272 error (" in thrown expression");
1273
1274 object = build_indirect_ref (exp, NULL_PTR);
1275 throw_type = build_eh_type (object);
1276
1277 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1278 {
1279 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1280 dtor_identifier, 0);
1281 cleanup = TREE_VALUE (cleanup);
1282 mark_addressable (cleanup);
1283 /* Pretend it's a normal function. */
1284 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1285 }
1286 }
1287
1288 if (cleanup == NULL_TREE)
1289 {
1290 cleanup = build_int_2 (0, 0);
1291 TREE_TYPE (cleanup) = cleanup_type;
1292 }
1293
1294 fn = get_identifier ("__cp_push_exception");
1295 if (IDENTIFIER_GLOBAL_VALUE (fn))
1296 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1297 else
1298 {
1299 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1300 as defined in exception.cc. */
1301 tree tmp;
1302 push_obstacks_nochange ();
1303 end_temporary_allocation ();
1304 tmp = tree_cons
1305 (NULL_TREE, ptr_type_node, tree_cons
1306 (NULL_TREE, ptr_type_node, tree_cons
1307 (NULL_TREE, cleanup_type, void_list_node)));
1308 fn = build_lang_decl (FUNCTION_DECL, fn,
1309 build_function_type (void_type_node, tmp));
1310 DECL_EXTERNAL (fn) = 1;
1311 TREE_PUBLIC (fn) = 1;
1312 DECL_ARTIFICIAL (fn) = 1;
1313 pushdecl_top_level (fn);
1314 make_function_rtl (fn);
1315 assemble_external (fn);
1316 pop_obstacks ();
1317 }
1318
1319 /* The throw expression is a full-expression. */
1320 exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
1321 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1322 (NULL_TREE, throw_type, expr_tree_cons
1323 (NULL_TREE, cleanup, NULL_TREE)));
1324 e = build_function_call (fn, e);
1325 expand_expr (e, const0_rtx, VOIDmode, 0);
1326 }
1327 else
1328 {
1329 /* rethrow current exception; note that it's no longer caught. */
1330
1331 tree fn = get_identifier ("__uncatch_exception");
1332 if (IDENTIFIER_GLOBAL_VALUE (fn))
1333 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1334 else
1335 {
1336 /* Declare void __uncatch_exception (void)
1337 as defined in exception.cc. */
1338 push_obstacks_nochange ();
1339 end_temporary_allocation ();
1340 fn = build_lang_decl (FUNCTION_DECL, fn,
1341 build_function_type (void_type_node,
1342 void_list_node));
1343 DECL_EXTERNAL (fn) = 1;
1344 TREE_PUBLIC (fn) = 1;
1345 DECL_ARTIFICIAL (fn) = 1;
1346 pushdecl_top_level (fn);
1347 make_function_rtl (fn);
1348 assemble_external (fn);
1349 pop_obstacks ();
1350 }
1351
1352 exp = build_function_call (fn, NULL_TREE);
1353 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1354 }
1355
1356 if (exceptions_via_longjmp)
1357 emit_throw ();
1358 else
1359 {
1360 /* This is the label that represents where in the code we were, when
1361 we got an exception. This needs to be updated when we rethrow an
1362 exception, so that the matching routine knows to search out. */
1363 label = gen_label_rtx ();
1364 emit_label (label);
1365
1366 expand_internal_throw (label);
1367 }
1368 }
1369
1370 /* Build a throw expression. */
1371
1372 tree
1373 build_throw (e)
1374 tree e;
1375 {
1376 if (e != error_mark_node)
1377 {
1378 if (processing_template_decl)
1379 return build_min (THROW_EXPR, void_type_node, e);
1380 e = build1 (THROW_EXPR, void_type_node, e);
1381 TREE_SIDE_EFFECTS (e) = 1;
1382 TREE_USED (e) = 1;
1383 }
1384 return e;
1385 }
This page took 0.093819 seconds and 4 git commands to generate.