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