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