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