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