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