]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/except.c
except.c (expand_start_catch_block): Fix catching a reference to pointer.
[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[6];
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 fields[5] = build_lang_field_decl
346 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
347 /* N.B.: The fourth field LEN is expected to be
348 the number of fields - 1, not the total number of fields. */
349 finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node);
350 t = build_pointer_type (t);
351
352 /* And now the function. */
353 fn = build_lang_decl (FUNCTION_DECL, fn,
354 build_function_type (t, void_list_node));
355 DECL_EXTERNAL (fn) = 1;
356 TREE_PUBLIC (fn) = 1;
357 DECL_ARTIFICIAL (fn) = 1;
358 pushdecl_top_level (fn);
359 make_function_rtl (fn);
360 assemble_external (fn);
361 pop_obstacks ();
362 }
363 return build_function_call (fn, NULL_TREE);
364 }
365
366 /* Retrieve a pointer to the cp_eh_info node for the current exception
367 and save it in the current binding level. */
368
369 static void
370 push_eh_info ()
371 {
372 tree decl, fn = call_eh_info ();
373
374 /* Remember the pointer to the current exception info; it won't change
375 during this catch block. */
376 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
377 TREE_TYPE (fn));
378 DECL_ARTIFICIAL (decl) = 1;
379 DECL_INITIAL (decl) = fn;
380 decl = pushdecl (decl);
381 cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
382 }
383
384 /* Returns a reference to the cp_eh_info node for the current exception. */
385
386 static tree
387 get_eh_info ()
388 {
389 /* Look for the pointer pushed in push_eh_info. */
390 tree t = lookup_name (get_identifier ("__exception_info"), 0);
391 return build_indirect_ref (t, NULL_PTR);
392 }
393
394 /* Returns a reference to the current exception object. */
395
396 static tree
397 get_eh_value ()
398 {
399 return build_component_ref (get_eh_info (), get_identifier ("value"),
400 NULL_TREE, 0);
401 }
402
403 /* Returns a reference to the current exception type. */
404
405 static tree
406 get_eh_type ()
407 {
408 return build_component_ref (get_eh_info (), get_identifier ("type"),
409 NULL_TREE, 0);
410 }
411
412 /* Returns a reference to whether or not the current exception
413 has been caught. */
414
415 static tree
416 get_eh_caught ()
417 {
418 return build_component_ref (get_eh_info (), get_identifier ("caught"),
419 NULL_TREE, 0);
420 }
421
422 /* Returns a reference to whether or not the current exception
423 has been caught. */
424
425 static tree
426 get_eh_handlers ()
427 {
428 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
429 NULL_TREE, 0);
430 }
431
432 /* Build a type value for use at runtime for a type that is matched
433 against by the exception handling system. */
434
435 static tree
436 build_eh_type_type (type)
437 tree type;
438 {
439 char *typestring;
440 tree exp;
441
442 if (type == error_mark_node)
443 return error_mark_node;
444
445 /* peel back references, so they match. */
446 if (TREE_CODE (type) == REFERENCE_TYPE)
447 type = TREE_TYPE (type);
448
449 /* Peel off cv qualifiers. */
450 type = TYPE_MAIN_VARIANT (type);
451
452 if (flag_rtti)
453 {
454 return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
455 }
456
457 typestring = build_overload_name (type, 1, 1);
458 exp = combine_strings (build_string (strlen (typestring)+1, typestring));
459 return build1 (ADDR_EXPR, ptr_type_node, exp);
460 }
461
462 /* Build a type value for use at runtime for a exp that is thrown or
463 matched against by the exception handling system. */
464
465 static tree
466 build_eh_type (exp)
467 tree exp;
468 {
469 if (flag_rtti)
470 {
471 exp = build_typeid (exp);
472 return build1 (ADDR_EXPR, ptr_type_node, exp);
473 }
474 return build_eh_type_type (TREE_TYPE (exp));
475 }
476
477 /* Build up a call to __cp_pop_exception, to destroy the exception object
478 for the current catch block. HANDLER is either true or false, telling
479 the library whether or not it is being called from an exception handler;
480 if it is, it avoids destroying the object on rethrow. */
481
482 static tree
483 do_pop_exception (handler)
484 tree handler;
485 {
486 tree fn, cleanup;
487 fn = get_identifier ("__cp_pop_exception");
488 if (IDENTIFIER_GLOBAL_VALUE (fn))
489 fn = IDENTIFIER_GLOBAL_VALUE (fn);
490 else
491 {
492 /* Declare void __cp_pop_exception (void *),
493 as defined in exception.cc. */
494 push_obstacks_nochange ();
495 end_temporary_allocation ();
496 fn = build_lang_decl
497 (FUNCTION_DECL, fn,
498 build_function_type (void_type_node, tree_cons
499 (NULL_TREE, ptr_type_node, tree_cons
500 (NULL_TREE, boolean_type_node,
501 void_list_node))));
502 DECL_EXTERNAL (fn) = 1;
503 TREE_PUBLIC (fn) = 1;
504 DECL_ARTIFICIAL (fn) = 1;
505 pushdecl_top_level (fn);
506 make_function_rtl (fn);
507 assemble_external (fn);
508 pop_obstacks ();
509 }
510
511 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
512 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
513 cleanup = build_function_call (fn, expr_tree_cons
514 (NULL_TREE, cleanup, expr_tree_cons
515 (NULL_TREE, handler, NULL_TREE)));
516 return cleanup;
517 }
518
519 /* This routine creates the cleanup for the current exception. */
520
521 static void
522 push_eh_cleanup ()
523 {
524 /* All cleanups must last longer than normal. */
525 int yes = suspend_momentary ();
526 expand_decl_cleanup_no_eh (NULL_TREE, do_pop_exception (boolean_false_node));
527 resume_momentary (yes);
528
529 expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
530 const0_rtx, VOIDmode, EXPAND_NORMAL);
531
532 /* We don't destroy the exception object on rethrow, so we can't use
533 the normal cleanup mechanism for it. */
534 expand_eh_region_start ();
535 }
536
537 /* call this to start a catch block. Typename is the typename, and identifier
538 is the variable to place the object in or NULL if the variable doesn't
539 matter. If typename is NULL, that means its a "catch (...)" or catch
540 everything. In that case we don't need to do any type checking.
541 (ie: it ends up as the "else" clause rather than an "else if" clause) */
542
543 void
544 expand_start_catch_block (declspecs, declarator)
545 tree declspecs, declarator;
546 {
547 rtx false_label_rtx;
548 tree decl = NULL_TREE;
549 tree init;
550
551 if (processing_template_decl)
552 {
553 if (declspecs)
554 {
555 decl = grokdeclarator (declarator, declspecs, CATCHPARM,
556 1, NULL_TREE);
557 pushdecl (decl);
558 decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
559 copy_to_permanent (declspecs),
560 NULL_TREE);
561 add_tree (decl);
562 }
563 return;
564 }
565
566 if (! doing_eh (1))
567 return;
568
569 /* If we are not doing setjmp/longjmp EH, because we are reordered
570 out of line, we arrange to rethrow in the outer context so as to
571 skip through the terminate region we are nested in, should we
572 encounter an exception in the catch handler. We also need to do
573 this because we are not physically within the try block, if any,
574 that contains this catch block.
575
576 Matches the end in expand_end_catch_block. */
577 if (! exceptions_via_longjmp)
578 expand_eh_region_start ();
579
580 /* Create a binding level for the eh_info and the exception object
581 cleanup. */
582 pushlevel (0);
583 expand_start_bindings (0);
584
585 false_label_rtx = gen_label_rtx ();
586 push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
587
588 emit_line_note (input_filename, lineno);
589
590 push_eh_info ();
591
592 if (declspecs)
593 {
594 decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
595
596 if (decl == NULL_TREE)
597 error ("invalid catch parameter");
598 }
599
600 if (decl)
601 {
602 tree exp;
603 rtx call_rtx, return_value_rtx;
604 tree init_type;
605
606 /* Make sure we mark the catch param as used, otherwise we'll get
607 a warning about an unused ((anonymous)). */
608 TREE_USED (decl) = 1;
609
610 /* Figure out the type that the initializer is. */
611 init_type = TREE_TYPE (decl);
612 if (TREE_CODE (init_type) != REFERENCE_TYPE
613 && TREE_CODE (init_type) != POINTER_TYPE)
614 init_type = build_reference_type (init_type);
615
616 exp = get_eh_value ();
617
618 /* Since pointers are passed by value, initialize a reference to
619 pointer catch parm with the address of the value slot. */
620 if (TREE_CODE (init_type) == REFERENCE_TYPE
621 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
622 exp = build_unary_op (ADDR_EXPR, exp, 1);
623
624 exp = expr_tree_cons (NULL_TREE,
625 build_eh_type_type (TREE_TYPE (decl)),
626 expr_tree_cons (NULL_TREE,
627 get_eh_type (),
628 expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
629 exp = build_function_call (CatchMatch, exp);
630 call_rtx = expand_call (exp, NULL_RTX, 0);
631 assemble_external (TREE_OPERAND (CatchMatch, 0));
632
633 return_value_rtx = hard_function_value (ptr_type_node, exp);
634
635 /* did the throw type match function return TRUE? */
636 emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
637 GET_MODE (return_value_rtx), 0, 0);
638
639 /* if it returned FALSE, jump over the catch block, else fall into it */
640 emit_jump_insn (gen_beq (false_label_rtx));
641
642 push_eh_cleanup ();
643
644 /* Create a binding level for the parm. */
645 pushlevel (0);
646 expand_start_bindings (0);
647
648 init = convert_from_reference (make_tree (init_type, call_rtx));
649
650 /* If the constructor for the catch parm exits via an exception, we
651 must call terminate. See eh23.C. */
652 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
653 {
654 /* Generate the copy constructor call directly so we can wrap it.
655 See also expand_default_init. */
656 init = ocp_convert (TREE_TYPE (decl), init,
657 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
658 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
659 TerminateFunctionCall);
660 }
661
662 /* Let `cp_finish_decl' know that this initializer is ok. */
663 DECL_INITIAL (decl) = init;
664 decl = pushdecl (decl);
665
666 cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
667 }
668 else
669 {
670 push_eh_cleanup ();
671
672 /* Create a binding level for the parm. */
673 pushlevel (0);
674 expand_start_bindings (0);
675
676 /* Fall into the catch all section. */
677 }
678
679 init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
680 expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
681
682 emit_line_note (input_filename, lineno);
683 }
684
685
686
687 /* Call this to end a catch block. Its responsible for emitting the
688 code to handle jumping back to the correct place, and for emitting
689 the label to jump to if this catch block didn't match. */
690
691 void
692 expand_end_catch_block ()
693 {
694 if (! doing_eh (1))
695 return;
696
697 /* Cleanup the EH parameter. */
698 expand_end_bindings (getdecls (), kept_level_p (), 0);
699 poplevel (kept_level_p (), 1, 0);
700
701 /* Matches push_eh_cleanup. */
702 expand_eh_region_end (do_pop_exception (boolean_true_node));
703
704 /* Cleanup the EH object. */
705 expand_end_bindings (getdecls (), kept_level_p (), 0);
706 poplevel (kept_level_p (), 1, 0);
707
708 if (! exceptions_via_longjmp)
709 {
710 /* If we are not doing setjmp/longjmp EH, we need an extra
711 region around the whole catch block to skip through the
712 terminate region we are nested in. */
713
714 tree t = make_node (RTL_EXPR);
715 TREE_TYPE (t) = void_type_node;
716 RTL_EXPR_RTL (t) = const0_rtx;
717 TREE_SIDE_EFFECTS (t) = 1;
718 do_pending_stack_adjust ();
719 start_sequence_for_rtl_expr (t);
720
721 expand_internal_throw (outer_context_label_stack->u.rlabel);
722
723 do_pending_stack_adjust ();
724 RTL_EXPR_SEQUENCE (t) = get_insns ();
725 end_sequence ();
726
727 /* For the rethrow region. */
728 expand_eh_region_end (t);
729 }
730
731 /* Fall to outside the try statement when done executing handler and
732 we fall off end of handler. This is jump Lresume in the
733 documentation. */
734 expand_goto (top_label_entry (&caught_return_label_stack));
735
736 expand_leftover_cleanups ();
737
738 /* label we emit to jump to if this catch block didn't match. */
739 /* This the closing } in the `if (eq) {' of the documentation. */
740 emit_label (pop_label_entry (&false_label_stack));
741 }
742
743 /* unwind the stack. */
744
745 static void
746 do_unwind (inner_throw_label)
747 rtx inner_throw_label;
748 {
749 #if defined (SPARC_STACK_ALIGN) /* was sparc */
750 /* This doesn't work for the flat model sparc, nor does it need to
751 as the default unwinder is only used to unwind non-flat frames. */
752 tree fcall;
753 tree params;
754 rtx next_pc;
755 rtx temp;
756
757 /* Call to __builtin_return_address. */
758 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
759 fcall = build_function_call (BuiltinReturnAddress, params);
760 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
761 /* In the return, the new pc is pc+8, as the value coming in is
762 really the address of the call insn, not the next insn. */
763 temp = gen_reg_rtx (Pmode);
764 emit_move_insn (temp, inner_throw_label);
765 emit_move_insn (next_pc, plus_constant (temp, -8));
766 emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
767 easy_expand_asm ("ret");
768 easy_expand_asm ("restore");
769 emit_barrier ();
770 #endif
771 #if defined (ARM_FRAME_RTX) /* was __arm */
772 if (flag_omit_frame_pointer)
773 sorry ("this implementation of exception handling requires a frame pointer");
774
775 emit_move_insn (stack_pointer_rtx,
776 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
777 emit_move_insn (hard_frame_pointer_rtx,
778 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
779 #endif
780 #if defined (TARGET_88000) /* was m88k */
781 rtx temp_frame = frame_pointer_rtx;
782
783 temp_frame = memory_address (Pmode, temp_frame);
784 temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
785
786 /* hopefully this will successfully pop the frame! */
787 emit_move_insn (frame_pointer_rtx, temp_frame);
788 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
789 emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
790 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
791 (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
792
793 #if 0
794 emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
795 -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
796
797 emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
798
799 emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
800 (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
801 #endif
802 #endif
803 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
804 tree fcall;
805 tree params;
806 rtx next_pc;
807
808 #if 0
809 /* I would like to do this here, but the move below doesn't seem to work. */
810 /* Call to __builtin_return_address. */
811 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
812 fcall = build_function_call (BuiltinReturnAddress, params);
813 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
814
815 emit_move_insn (next_pc, inner_throw_label);
816 /* So, for now, just pass throw label to stack unwinder. */
817 #endif
818 params = expr_tree_cons (NULL_TREE, make_tree (ptr_type_node,
819 inner_throw_label), NULL_TREE);
820
821 do_function_call (Unwind, params, NULL_TREE);
822 assemble_external (TREE_OPERAND (Unwind, 0));
823 emit_barrier ();
824 #endif
825 }
826
827
828 /* Is called from expand_exception_blocks to generate the code in a function
829 to "throw" if anything in the function needs to perform a throw.
830
831 expands "throw" as the following pseudo code:
832
833 throw:
834 eh = find_first_exception_match (saved_pc);
835 if (!eh) goto gotta_rethrow_it;
836 goto eh;
837
838 gotta_rethrow_it:
839 saved_pc = __builtin_return_address (0);
840 pop_to_previous_level ();
841 goto throw; */
842
843 void
844 expand_builtin_throw ()
845 {
846 #ifndef DWARF2_UNWIND_INFO
847 tree fcall;
848 tree params;
849 rtx handler;
850 rtx saved_pcnthrow;
851 rtx next_pc;
852 rtx gotta_rethrow_it;
853 rtx gotta_call_terminate;
854 rtx after_unwind;
855 rtx top_of_loop;
856 tree t;
857 rtx x;
858
859 if (! doing_eh (0))
860 return;
861
862 if (! throw_used)
863 return;
864
865 params = void_list_node;
866 t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
867 NULL_TREE);
868 start_function (decl_tree_cons (NULL_TREE,
869 get_identifier ("void"),
870 decl_tree_cons (NULL_TREE,
871 get_identifier ("static"),
872 NULL_TREE)),
873 t, NULL_TREE, 0);
874 store_parm_decls ();
875 pushlevel (0);
876 clear_last_expr ();
877 push_momentary ();
878 expand_start_bindings (0);
879
880 gotta_rethrow_it = gen_label_rtx ();
881 gotta_call_terminate = gen_label_rtx ();
882
883 /* These two can be frontend specific. If wanted, they can go in
884 expand_throw. */
885 /* Do we have a valid object we are throwing? */
886 t = call_eh_info ();
887 emit_cmp_insn (expand_expr (t, NULL_RTX, Pmode, 0),
888 const0_rtx, EQ, NULL_RTX,
889 GET_MODE (DECL_RTL (t)), 0, 0);
890 emit_jump_insn (gen_beq (gotta_call_terminate));
891
892 /* search for an exception handler for the saved_pc */
893 handler = do_function_call (FirstExceptionMatch,
894 expr_tree_cons (NULL_TREE, saved_pc,
895 NULL_TREE),
896 ptr_type_node);
897 assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
898
899 /* did we find one? */
900 emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
901 GET_MODE (handler), 0, 0);
902
903 /* if not, jump to gotta_rethrow_it */
904 emit_jump_insn (gen_beq (gotta_rethrow_it));
905
906 {
907 rtx ret_val, x;
908 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
909 0, hard_frame_pointer_rtx);
910
911 /* Set it up so that we continue at the handler. */
912 emit_move_insn (ret_val, handler);
913 #ifdef RETURN_ADDR_OFFSET
914 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
915 if (x != ret_val)
916 emit_move_insn (ret_val, x);
917 #endif
918
919 expand_null_return ();
920 }
921
922 top_of_loop = gen_label_rtx ();
923 emit_label (top_of_loop);
924
925 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
926 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
927 {
928 saved_pcnthrow = gen_reg_rtx (Pmode);
929 emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
930 NULL_TREE));
931 }
932 #endif
933
934 /* Call to __builtin_return_address. */
935 #if defined (ARM_FRAME_RTX) /* was __arm */
936 /* This should be moved into arm.h:RETURN_ADDR_RTX */
937 /* This replaces a 'call' to __builtin_return_address */
938 next_pc = gen_reg_rtx (Pmode);
939 emit_move_insn (next_pc,
940 gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
941 #else
942 params = expr_tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
943 fcall = build_function_call (BuiltinReturnAddress, params);
944 next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
945 #endif
946
947 /* Did __builtin_return_address return a valid address? */
948 emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
949 GET_MODE (next_pc), 0, 0);
950
951 emit_jump_insn (gen_beq (gotta_call_terminate));
952
953 next_pc = eh_outer_context (next_pc);
954
955 /* Yes it did. */
956 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
957 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
958 {
959 rtx x;
960
961 x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
962 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
963 next_pc);
964 #ifdef FUNCTION_OUTGOING_VALUE
965 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
966 validize_mem (gen_rtx (MEM, Pmode,
967 plus_constant (saved_pcnthrow,
968 GET_MODE_SIZE (Pmode)))));
969 emit_insn (gen_rtx (USE, VOIDmode,
970 FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
971 #endif
972 }
973 else
974 #endif
975 emit_move_insn (eh_saved_pc_rtx, next_pc);
976
977 after_unwind = gen_label_rtx ();
978 do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
979
980 emit_label (after_unwind);
981
982 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
983 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
984 {
985 t = build_function_type (void_type_node, void_list_node);
986 t = make_tree (build_pointer_type (t),
987 hard_function_value (ptr_type_node,
988 NULL_TREE));
989 t = build_function_call (t, NULL_TREE);
990 expand_expr (t, const0_rtx, VOIDmode, 0);
991 }
992 else
993 #endif
994 emit_throw ();
995
996 /* no it didn't --> therefore we need to call terminate */
997 emit_label (gotta_call_terminate);
998 do_function_call (Terminate, NULL_TREE, NULL_TREE);
999 assemble_external (TREE_OPERAND (Terminate, 0));
1000
1001 {
1002 rtx ret_val, x;
1003 /* code to deal with unwinding and looking for it again */
1004 emit_label (gotta_rethrow_it);
1005 ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
1006 0, hard_frame_pointer_rtx);
1007
1008 /* Set it up so that we continue inside, at the top of the loop. */
1009 emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
1010 #ifdef RETURN_ADDR_OFFSET
1011 x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
1012 if (x != ret_val)
1013 emit_move_insn (ret_val, x);
1014 #endif
1015
1016 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
1017 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
1018 {
1019 rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
1020 "__eh_pcnthrow"),
1021 NULL_RTX, 1,
1022 Pmode, 0);
1023 /* This is to get a version of throw that will throw properly. */
1024 emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
1025 plus_constant (x, GET_MODE_SIZE (Pmode)))),
1026 throw_libfunc);
1027 #ifdef FUNCTION_OUTGOING_VALUE
1028 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
1029 x);
1030 emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
1031 #endif
1032 }
1033 #endif
1034
1035 /* Fall into epilogue to unwind prologue. */
1036 }
1037
1038 expand_end_bindings (getdecls (), 1, 0);
1039 poplevel (1, 0, 0);
1040 pop_momentary ();
1041
1042 finish_function (lineno, 0, 0);
1043 #endif /* DWARF2_UNWIND_INFO */
1044 }
1045
1046 /* An exception spec is implemented more or less like:
1047
1048 try {
1049 function body;
1050 } catch (...) {
1051 void *p[] = { typeid(raises) };
1052 __check_eh_spec (p, count);
1053 }
1054
1055 __check_eh_spec in exception.cc handles all the details. */
1056
1057 void
1058 expand_start_eh_spec ()
1059 {
1060 expand_start_try_stmts ();
1061 }
1062
1063 static void
1064 expand_end_eh_spec (raises)
1065 tree raises;
1066 {
1067 tree tmp, fn, decl, types = NULL_TREE;
1068 int count = 0;
1069
1070 expand_start_all_catch ();
1071 expand_start_catch_block (NULL_TREE, NULL_TREE);
1072
1073 /* Build up an array of type_infos. */
1074 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
1075 {
1076 types = expr_tree_cons
1077 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
1078 ++count;
1079 }
1080
1081 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
1082 TREE_HAS_CONSTRUCTOR (types) = 1;
1083
1084 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
1085 tmp = build_array_type (const_ptr_type_node, NULL_TREE);
1086 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
1087 DECL_ARTIFICIAL (decl) = 1;
1088 DECL_INITIAL (decl) = types;
1089 cp_finish_decl (decl, types, NULL_TREE, 0, 0);
1090
1091 decl = decay_conversion (decl);
1092
1093 fn = get_identifier ("__check_eh_spec");
1094 if (IDENTIFIER_GLOBAL_VALUE (fn))
1095 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1096 else
1097 {
1098 push_obstacks_nochange ();
1099 end_temporary_allocation ();
1100
1101 tmp = tree_cons
1102 (NULL_TREE, integer_type_node, tree_cons
1103 (NULL_TREE, TREE_TYPE (decl), void_list_node));
1104 tmp = build_function_type (void_type_node, tmp);
1105
1106 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
1107 DECL_EXTERNAL (fn) = 1;
1108 TREE_PUBLIC (fn) = 1;
1109 DECL_ARTIFICIAL (fn) = 1;
1110 TREE_THIS_VOLATILE (fn) = 1;
1111 pushdecl_top_level (fn);
1112 make_function_rtl (fn);
1113 assemble_external (fn);
1114 pop_obstacks ();
1115 }
1116
1117 tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
1118 (NULL_TREE, decl, NULL_TREE));
1119 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
1120 expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1121
1122 expand_end_catch_block ();
1123 expand_end_all_catch ();
1124 }
1125
1126 /* This is called to expand all the toplevel exception handling
1127 finalization for a function. It should only be called once per
1128 function. */
1129
1130 void
1131 expand_exception_blocks ()
1132 {
1133 do_pending_stack_adjust ();
1134 push_to_sequence (catch_clauses);
1135 expand_leftover_cleanups ();
1136 do_pending_stack_adjust ();
1137 catch_clauses = get_insns ();
1138 end_sequence ();
1139
1140 /* Do this after we expand leftover cleanups, so that the
1141 expand_eh_region_end that expand_end_eh_spec does will match the
1142 right expand_eh_region_start, and make sure it comes out before
1143 the terminate protected region. */
1144 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1145 {
1146 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1147 do_pending_stack_adjust ();
1148 push_to_sequence (catch_clauses);
1149 expand_leftover_cleanups ();
1150 do_pending_stack_adjust ();
1151 catch_clauses = get_insns ();
1152 end_sequence ();
1153 }
1154
1155 if (catch_clauses)
1156 {
1157 rtx funcend = gen_label_rtx ();
1158 emit_jump (funcend);
1159
1160 /* We cannot protect n regions this way if we must flow into the
1161 EH region through the top of the region, as we have to with
1162 the setjmp/longjmp approach. */
1163 if (exceptions_via_longjmp == 0)
1164 {
1165 /* Is this necessary? */
1166 assemble_external (TREE_OPERAND (Terminate, 0));
1167
1168 expand_eh_region_start ();
1169 }
1170
1171 emit_insns (catch_clauses);
1172 catch_clauses = NULL_RTX;
1173
1174 if (exceptions_via_longjmp == 0)
1175 expand_eh_region_end (TerminateFunctionCall);
1176
1177 expand_leftover_cleanups ();
1178
1179 emit_label (funcend);
1180 }
1181 }
1182
1183 tree
1184 start_anon_func ()
1185 {
1186 static int counter = 0;
1187 int old_interface_unknown = interface_unknown;
1188 char name[32];
1189 tree params;
1190 tree t;
1191
1192 push_cp_function_context (NULL_TREE);
1193 push_to_top_level ();
1194
1195 /* No need to mangle this. */
1196 push_lang_context (lang_name_c);
1197
1198 interface_unknown = 1;
1199
1200 params = void_list_node;
1201 /* tcf stands for throw clean funciton. */
1202 sprintf (name, "__tcf_%d", counter++);
1203 t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1204 NULL_TREE);
1205 start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1206 void_list_node),
1207 t, NULL_TREE, 0);
1208 store_parm_decls ();
1209 pushlevel (0);
1210 clear_last_expr ();
1211 push_momentary ();
1212 expand_start_bindings (0);
1213 emit_line_note (input_filename, lineno);
1214
1215 interface_unknown = old_interface_unknown;
1216
1217 pop_lang_context ();
1218
1219 return current_function_decl;
1220 }
1221
1222 void
1223 end_anon_func ()
1224 {
1225 expand_end_bindings (getdecls (), 1, 0);
1226 poplevel (1, 0, 0);
1227 pop_momentary ();
1228
1229 finish_function (lineno, 0, 0);
1230
1231 pop_from_top_level ();
1232 pop_cp_function_context (NULL_TREE);
1233 }
1234
1235 /* Expand a throw statement. This follows the following
1236 algorithm:
1237
1238 1. Allocate space to save the current PC onto the stack.
1239 2. Generate and emit a label and save its address into the
1240 newly allocated stack space since we can't save the pc directly.
1241 3. If this is the first call to throw in this function:
1242 generate a label for the throw block
1243 4. jump to the throw block label. */
1244
1245 void
1246 expand_throw (exp)
1247 tree exp;
1248 {
1249 rtx label;
1250 tree fn;
1251 static tree cleanup_type;
1252
1253 if (! doing_eh (1))
1254 return;
1255
1256 if (exp)
1257 {
1258 tree throw_type;
1259 tree cleanup = NULL_TREE, e;
1260
1261 /* throw expression */
1262 /* First, decay it. */
1263 exp = decay_conversion (exp);
1264
1265 /* cleanup_type is void (*)(void *, int),
1266 the internal type of a destructor. */
1267 if (cleanup_type == NULL_TREE)
1268 {
1269 push_obstacks_nochange ();
1270 end_temporary_allocation ();
1271 cleanup_type = build_pointer_type
1272 (build_function_type
1273 (void_type_node, tree_cons
1274 (NULL_TREE, ptr_type_node, tree_cons
1275 (NULL_TREE, integer_type_node, void_list_node))));
1276 pop_obstacks ();
1277 }
1278
1279 if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1280 {
1281 throw_type = build_eh_type (exp);
1282 exp = build_reinterpret_cast (ptr_type_node, exp);
1283 }
1284 else
1285 {
1286 tree object;
1287
1288 /* Make a copy of the thrown object. WP 15.1.5 */
1289 exp = build_new (NULL_TREE, TREE_TYPE (exp),
1290 build_expr_list (NULL_TREE, exp),
1291 0);
1292
1293 if (exp == error_mark_node)
1294 error (" in thrown expression");
1295
1296 object = build_indirect_ref (exp, NULL_PTR);
1297 throw_type = build_eh_type (object);
1298
1299 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
1300 {
1301 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
1302 dtor_identifier, 0);
1303 cleanup = TREE_VALUE (cleanup);
1304 mark_addressable (cleanup);
1305 /* Pretend it's a normal function. */
1306 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
1307 }
1308 }
1309
1310 if (cleanup == NULL_TREE)
1311 {
1312 cleanup = build_int_2 (0, 0);
1313 TREE_TYPE (cleanup) = cleanup_type;
1314 }
1315
1316 fn = get_identifier ("__cp_push_exception");
1317 if (IDENTIFIER_GLOBAL_VALUE (fn))
1318 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1319 else
1320 {
1321 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1322 as defined in exception.cc. */
1323 tree tmp;
1324 push_obstacks_nochange ();
1325 end_temporary_allocation ();
1326 tmp = tree_cons
1327 (NULL_TREE, ptr_type_node, tree_cons
1328 (NULL_TREE, ptr_type_node, tree_cons
1329 (NULL_TREE, cleanup_type, void_list_node)));
1330 fn = build_lang_decl (FUNCTION_DECL, fn,
1331 build_function_type (void_type_node, tmp));
1332 DECL_EXTERNAL (fn) = 1;
1333 TREE_PUBLIC (fn) = 1;
1334 DECL_ARTIFICIAL (fn) = 1;
1335 pushdecl_top_level (fn);
1336 make_function_rtl (fn);
1337 assemble_external (fn);
1338 pop_obstacks ();
1339 }
1340
1341 /* The throw expression is a full-expression. */
1342 exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
1343 e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
1344 (NULL_TREE, throw_type, expr_tree_cons
1345 (NULL_TREE, cleanup, NULL_TREE)));
1346 e = build_function_call (fn, e);
1347 expand_expr (e, const0_rtx, VOIDmode, 0);
1348 }
1349 else
1350 {
1351 /* rethrow current exception; note that it's no longer caught. */
1352
1353 tree fn = get_identifier ("__uncatch_exception");
1354 if (IDENTIFIER_GLOBAL_VALUE (fn))
1355 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1356 else
1357 {
1358 /* Declare void __uncatch_exception (void)
1359 as defined in exception.cc. */
1360 push_obstacks_nochange ();
1361 end_temporary_allocation ();
1362 fn = build_lang_decl (FUNCTION_DECL, fn,
1363 build_function_type (void_type_node,
1364 void_list_node));
1365 DECL_EXTERNAL (fn) = 1;
1366 TREE_PUBLIC (fn) = 1;
1367 DECL_ARTIFICIAL (fn) = 1;
1368 pushdecl_top_level (fn);
1369 make_function_rtl (fn);
1370 assemble_external (fn);
1371 pop_obstacks ();
1372 }
1373
1374 exp = build_function_call (fn, NULL_TREE);
1375 expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
1376 }
1377
1378 if (exceptions_via_longjmp)
1379 emit_throw ();
1380 else
1381 {
1382 /* This is the label that represents where in the code we were, when
1383 we got an exception. This needs to be updated when we rethrow an
1384 exception, so that the matching routine knows to search out. */
1385 label = gen_label_rtx ();
1386 emit_label (label);
1387
1388 expand_internal_throw (label);
1389 }
1390 }
1391
1392 /* Build a throw expression. */
1393
1394 tree
1395 build_throw (e)
1396 tree e;
1397 {
1398 if (e != error_mark_node)
1399 {
1400 if (processing_template_decl)
1401 return build_min (THROW_EXPR, void_type_node, e);
1402 e = build1 (THROW_EXPR, void_type_node, e);
1403 TREE_SIDE_EFFECTS (e) = 1;
1404 TREE_USED (e) = 1;
1405 }
1406 return e;
1407 }
This page took 0.096266 seconds and 5 git commands to generate.