]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/except.c
ae64e78b3d6f07b0cee36bf47cec695ec235eb8a
[gcc.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 Free Software Foundation, Inc.
4 Contributed by Michael Tiemann <tiemann@cygnus.com>
5 Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
6 initial re-implementation courtesy Tad Hunt.
7
8 This file is part of GNU CC.
9
10 GNU CC is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GNU CC is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GNU CC; see the file COPYING. If not, write to
22 the Free Software Foundation, 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25
26 #include "config.h"
27 #include "system.h"
28 #include "tree.h"
29 #include "rtl.h"
30 #include "cp-tree.h"
31 #include "flags.h"
32 #include "obstack.h"
33 #include "expr.h"
34 #include "output.h"
35 #include "except.h"
36 #include "defaults.h"
37 #include "toplev.h"
38 #include "eh-common.h"
39
40 static void push_eh_cleanup PARAMS ((void));
41 static tree build_eh_type_type PARAMS ((tree));
42 static tree call_eh_info PARAMS ((void));
43 static void push_eh_info PARAMS ((void));
44 static tree get_eh_info PARAMS ((void));
45 static tree get_eh_value PARAMS ((void));
46 #if 0
47 static tree get_eh_type PARAMS ((void));
48 static tree get_eh_caught PARAMS ((void));
49 static tree get_eh_handlers PARAMS ((void));
50 #endif
51 static tree do_pop_exception PARAMS ((void));
52 static tree build_eh_type_type_ref PARAMS ((tree));
53 static tree build_terminate_handler PARAMS ((void));
54 static tree alloc_eh_object PARAMS ((tree));
55 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
56 static void initialize_handler_parm PARAMS ((tree));
57 static tree expand_throw PARAMS ((tree));
58 static int decl_is_java_type PARAMS ((tree decl, int err));
59
60 #if 0
61 /* This is the startup, and finish stuff per exception table. */
62
63 /* XXX - Tad: exception handling section */
64 #ifndef EXCEPT_SECTION_ASM_OP
65 #define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits"
66 #endif
67
68 #ifdef EXCEPT_SECTION_ASM_OP
69
70 /* on machines which support it, the exception table lives in another section,
71 but it needs a label so we can reference it... This sets up that
72 label! */
73 asm (EXCEPT_SECTION_ASM_OP);
74 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
75 asm (TEXT_SECTION_ASM_OP);
76
77 #endif /* EXCEPT_SECTION_ASM_OP */
78
79 #ifdef EXCEPT_SECTION_ASM_OP
80
81 /* we need to know where the end of the exception table is... so this
82 is how we do it! */
83
84 asm (EXCEPT_SECTION_ASM_OP);
85 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
86 asm (TEXT_SECTION_ASM_OP);
87
88 #endif /* EXCEPT_SECTION_ASM_OP */
89
90 #endif
91
92 #include "decl.h"
93 #include "insn-flags.h"
94 #include "obstack.h"
95
96 /* In a given translation unit we are constrained to catch only C++
97 types or only Java types. `catch_language' holds the current type,
98 and `catch_language_init' registers whether `catch_language' has
99 been set. */
100
101 static int catch_language_init = 0;
102 static int catch_language;
103
104 /* ======================================================================
105 Briefly the algorithm works like this:
106
107 When a constructor or start of a try block is encountered,
108 push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a
109 new entry in the unwind protection stack and returns a label to
110 output to start the protection for that block.
111
112 When a destructor or end try block is encountered, pop_eh_entry
113 (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
114 created when push_eh_entry () was called. The eh_entry structure
115 contains three things at this point. The start protect label,
116 the end protect label, and the exception handler label. The end
117 protect label should be output before the call to the destructor
118 (if any). If it was a destructor, then its parse tree is stored
119 in the finalization variable in the eh_entry structure. Otherwise
120 the finalization variable is set to NULL to reflect the fact that
121 it is the end of a try block. Next, this modified eh_entry node
122 is enqueued in the finalizations queue by calling
123 enqueue_eh_entry (&queue,entry).
124
125 +---------------------------------------------------------------+
126 |XXX: Will need modification to deal with partially |
127 | constructed arrays of objects |
128 | |
129 | Basically, this consists of keeping track of how many |
130 | of the objects have been constructed already (this |
131 | should be in a register though, so that shouldn't be a |
132 | problem. |
133 +---------------------------------------------------------------+
134
135 When a catch block is encountered, there is a lot of work to be
136 done.
137
138 Since we don't want to generate the catch block inline with the
139 regular flow of the function, we need to have some way of doing
140 so. Luckily, we can use sequences to defer the catch sections.
141 When the start of a catch block is encountered, we start the
142 sequence. After the catch block is generated, we end the
143 sequence.
144
145 Next we must insure that when the catch block is executed, all
146 finalizations for the matching try block have been completed. If
147 any of those finalizations throw an exception, we must call
148 terminate according to the ARM (section r.15.6.1). What this
149 means is that we need to dequeue and emit finalizations for each
150 entry in the eh_queue until we get to an entry with a NULL
151 finalization field. For any of the finalization entries, if it
152 is not a call to terminate (), we must protect it by giving it
153 another start label, end label, and exception handler label,
154 setting its finalization tree to be a call to terminate (), and
155 enqueue'ing this new eh_entry to be output at an outer level.
156 Finally, after all that is done, we can get around to outputting
157 the catch block which basically wraps all the "catch (...) {...}"
158 statements in a big if/then/else construct that matches the
159 correct block to call.
160
161 ===================================================================== */
162
163 /* ====================================================================== */
164
165 /* sets up all the global eh stuff that needs to be initialized at the
166 start of compilation. */
167
168 void
169 init_exception_processing ()
170 {
171 /* void vtype () */
172 tree vtype = build_function_type (void_type_node, void_list_node);
173
174 if (flag_honor_std)
175 push_namespace (get_identifier ("std"));
176 terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
177 TREE_THIS_VOLATILE (terminate_node) = 1;
178 TREE_NOTHROW (terminate_node) = 1;
179 if (flag_honor_std)
180 pop_namespace ();
181
182 set_exception_lang_code (EH_LANG_C_plus_plus);
183 set_exception_version_code (1);
184
185 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
186 be protected with __terminate. */
187 protect_cleanup_actions_with_terminate = 1;
188 }
189
190 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
191
192 static tree
193 call_eh_info ()
194 {
195 tree fn;
196
197 fn = get_identifier ("__start_cp_handler");
198 if (IDENTIFIER_GLOBAL_VALUE (fn))
199 fn = IDENTIFIER_GLOBAL_VALUE (fn);
200 else
201 {
202 tree t1, t, fields[7];
203
204 /* Declare cp_eh_info * __start_cp_handler (void),
205 as defined in exception.cc. */
206
207 /* struct cp_eh_info. This must match exception.cc. Note that this
208 type is not pushed anywhere. */
209 t1= make_aggr_type (RECORD_TYPE);
210 fields[0] = build_lang_decl (FIELD_DECL,
211 get_identifier ("handler_label"), ptr_type_node);
212 fields[1] = build_lang_decl (FIELD_DECL,
213 get_identifier ("dynamic_handler_chain"), ptr_type_node);
214 fields[2] = build_lang_decl (FIELD_DECL,
215 get_identifier ("info"), ptr_type_node);
216 fields[3] = build_lang_decl (FIELD_DECL,
217 get_identifier ("table_index"), ptr_type_node);
218 /* N.B.: The fourth field LEN is expected to be
219 the number of fields - 1, not the total number of fields. */
220 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
221 t1 = build_pointer_type (t1);
222
223 t1= make_aggr_type (RECORD_TYPE);
224 fields[0] = build_lang_decl (FIELD_DECL,
225 get_identifier ("match_function"), ptr_type_node);
226 fields[1] = build_lang_decl (FIELD_DECL,
227 get_identifier ("language"), short_integer_type_node);
228 fields[2] = build_lang_decl (FIELD_DECL,
229 get_identifier ("version"), short_integer_type_node);
230 /* N.B.: The fourth field LEN is expected to be
231 the number of fields - 1, not the total number of fields. */
232 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
233 t = make_aggr_type (RECORD_TYPE);
234 fields[0] = build_lang_decl (FIELD_DECL,
235 get_identifier ("eh_info"), t1);
236 fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
237 ptr_type_node);
238 fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
239 ptr_type_node);
240 fields[3] = build_lang_decl
241 (FIELD_DECL, get_identifier ("cleanup"),
242 build_pointer_type (build_function_type
243 (ptr_type_node, tree_cons
244 (NULL_TREE, ptr_type_node, void_list_node))));
245 fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
246 boolean_type_node);
247 fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
248 build_pointer_type (t));
249 fields[6] = build_lang_decl
250 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
251 /* N.B.: The fourth field LEN is expected to be
252 the number of fields - 1, not the total number of fields. */
253 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
254 t = build_pointer_type (t);
255
256 /* And now the function. */
257 fn = push_library_fn (fn, build_function_type (t, void_list_node));
258 }
259 return build_function_call (fn, NULL_TREE);
260 }
261
262 /* Retrieve a pointer to the cp_eh_info node for the current exception
263 and save it in the current binding level. */
264
265 static void
266 push_eh_info ()
267 {
268 tree decl, fn = call_eh_info ();
269
270 /* Remember the pointer to the current exception info; it won't change
271 during this catch block. */
272 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
273 TREE_TYPE (fn));
274 DECL_ARTIFICIAL (decl) = 1;
275 DECL_INITIAL (decl) = fn;
276 decl = pushdecl (decl);
277 cp_finish_decl (decl, fn, NULL_TREE, 0);
278 }
279
280 /* Returns a reference to the cp_eh_info node for the current exception. */
281
282 static tree
283 get_eh_info ()
284 {
285 /* Look for the pointer pushed in push_eh_info. */
286 tree t = lookup_name (get_identifier ("__exception_info"), 0);
287 return build_indirect_ref (t, NULL_PTR);
288 }
289
290 /* Returns a reference to the current exception object. */
291
292 static tree
293 get_eh_value ()
294 {
295 return build_component_ref (get_eh_info (), get_identifier ("value"),
296 NULL_TREE, 0);
297 }
298
299 /* Returns a reference to the current exception type. */
300
301 #if 0
302 static tree
303 get_eh_type ()
304 {
305 return build_component_ref (get_eh_info (), get_identifier ("type"),
306 NULL_TREE, 0);
307 }
308
309 /* Returns a reference to whether or not the current exception
310 has been caught. */
311
312 static tree
313 get_eh_caught ()
314 {
315 return build_component_ref (get_eh_info (), get_identifier ("caught"),
316 NULL_TREE, 0);
317 }
318
319 /* Returns a reference to whether or not the current exception
320 has been caught. */
321
322 static tree
323 get_eh_handlers ()
324 {
325 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
326 NULL_TREE, 0);
327 }
328 #endif
329
330 /* Build a type value for use at runtime for a type that is matched
331 against by the exception handling system. */
332
333 static tree
334 build_eh_type_type (type)
335 tree type;
336 {
337 if (type == error_mark_node)
338 return error_mark_node;
339
340 /* peel back references, so they match. */
341 if (TREE_CODE (type) == REFERENCE_TYPE)
342 type = TREE_TYPE (type);
343
344 /* Peel off cv qualifiers. */
345 type = TYPE_MAIN_VARIANT (type);
346
347 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
348 }
349
350 /* Build the address of a typeinfo decl for use in the runtime
351 matching field of the new exception model */
352
353 static tree
354 build_eh_type_type_ref (type)
355 tree type;
356 {
357 tree exp;
358
359 if (type == error_mark_node)
360 return error_mark_node;
361
362 /* peel back references, so they match. */
363 if (TREE_CODE (type) == REFERENCE_TYPE)
364 type = TREE_TYPE (type);
365
366 /* Peel off cv qualifiers. */
367 type = TYPE_MAIN_VARIANT (type);
368
369 exp = get_tinfo_decl (type);
370 mark_used (exp);
371 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
372
373 return (exp);
374 }
375
376 /* This routine is called to mark all the symbols representing runtime
377 type functions in the exception table as having been referenced.
378 This will make sure code is emitted for them. Called from finish_file. */
379 void
380 mark_all_runtime_matches ()
381 {
382 int x,num;
383 void **ptr;
384 tree exp;
385
386 num = find_all_handler_type_matches (&ptr);
387 if (num == 0 || ptr == NULL)
388 return;
389
390 for (x=0; x <num; x++)
391 {
392 exp = (tree) ptr[x];
393 if (TREE_CODE (exp) == ADDR_EXPR)
394 {
395 exp = TREE_OPERAND (exp, 0);
396 if (TREE_CODE (exp) == FUNCTION_DECL)
397 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
398 }
399 }
400
401 free (ptr);
402 }
403
404 /* Build up a call to __cp_pop_exception, to destroy the exception object
405 for the current catch block. HANDLER is either true or false, telling
406 the library whether or not it is being called from an exception handler;
407 if it is, it avoids destroying the object on rethrow. */
408
409 static tree
410 do_pop_exception ()
411 {
412 tree fn, cleanup;
413 fn = get_identifier ("__cp_pop_exception");
414 if (IDENTIFIER_GLOBAL_VALUE (fn))
415 fn = IDENTIFIER_GLOBAL_VALUE (fn);
416 else
417 {
418 /* Declare void __cp_pop_exception (void *),
419 as defined in exception.cc. */
420 fn = push_void_library_fn
421 (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
422 /* This can throw if the destructor for the exception throws. */
423 TREE_NOTHROW (fn) = 0;
424 }
425
426 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
427 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
428 cleanup = build_function_call (fn, tree_cons
429 (NULL_TREE, cleanup, NULL_TREE));
430 return cleanup;
431 }
432
433 /* This routine creates the cleanup for the current exception. */
434
435 static void
436 push_eh_cleanup ()
437 {
438 finish_decl_cleanup (NULL_TREE, do_pop_exception ());
439 }
440
441 /* Build up a call to terminate on the function obstack, for use as an
442 exception handler. */
443
444 static tree
445 build_terminate_handler ()
446 {
447 return build_function_call (terminate_node, NULL_TREE);
448 }
449
450 /* Return nonzero value if DECL is a Java type suitable for catch or
451 throw. */
452
453 static int
454 decl_is_java_type (decl, err)
455 tree decl;
456 int err;
457 {
458 int r = (TREE_CODE (decl) == POINTER_TYPE
459 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
460 && TYPE_FOR_JAVA (TREE_TYPE (decl)));
461
462 if (err)
463 {
464 if (TREE_CODE (decl) == REFERENCE_TYPE
465 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
466 && TYPE_FOR_JAVA (TREE_TYPE (decl)))
467 {
468 /* Can't throw a reference. */
469 cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
470 decl);
471 }
472
473 if (r)
474 {
475 tree jthrow_node
476 = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
477 if (jthrow_node == NULL_TREE)
478 fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
479 jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
480
481 if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
482 {
483 /* Thrown object must be a Throwable. */
484 cp_error ("type `%T' is not derived from `java::lang::Throwable'",
485 TREE_TYPE (decl));
486 }
487 }
488 }
489
490 return r;
491 }
492
493 /* Initialize the catch parameter DECL. */
494
495 static void
496 initialize_handler_parm (decl)
497 tree decl;
498 {
499 tree exp;
500 tree init;
501 tree init_type;
502 int lang;
503
504 /* Make sure we mark the catch param as used, otherwise we'll get a
505 warning about an unused ((anonymous)). */
506 TREE_USED (decl) = 1;
507
508 /* Figure out the type that the initializer is. */
509 init_type = TREE_TYPE (decl);
510 if (TREE_CODE (init_type) != REFERENCE_TYPE
511 && TREE_CODE (init_type) != POINTER_TYPE)
512 init_type = build_reference_type (init_type);
513
514 if (decl_is_java_type (init_type, 0))
515 {
516 tree fn
517 = builtin_function ("_Jv_exception_info",
518 build_function_type (ptr_type_node,
519 tree_cons (NULL_TREE,
520 void_type_node,
521 NULL_TREE)),
522 0, NOT_BUILT_IN, NULL_PTR);
523
524 exp = build (CALL_EXPR, ptr_type_node,
525 build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
526 fn),
527 NULL_TREE, NULL_TREE);
528 TREE_SIDE_EFFECTS (exp) = 1;
529 lang = EH_LANG_Java;
530
531 set_exception_lang_code (EH_LANG_Java);
532 set_exception_version_code (1);
533 }
534 else
535 {
536 exp = get_eh_value ();
537 lang = EH_LANG_C_plus_plus;
538 }
539
540 if (catch_language_init)
541 {
542 if (lang != catch_language)
543 error ("mixing C++ and Java `catch'es in single translation unit");
544 }
545 else
546 {
547 catch_language_init = 1;
548 catch_language = lang;
549 }
550
551 /* Since pointers are passed by value, initialize a reference to
552 pointer catch parm with the address of the value slot. */
553 if (TREE_CODE (init_type) == REFERENCE_TYPE
554 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
555 exp = build_unary_op (ADDR_EXPR, exp, 1);
556
557 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
558
559 init = convert_from_reference (exp);
560
561 /* If the constructor for the catch parm exits via an exception, we
562 must call terminate. See eh23.C. */
563 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
564 {
565 /* Generate the copy constructor call directly so we can wrap it.
566 See also expand_default_init. */
567 init = ocp_convert (TREE_TYPE (decl), init,
568 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
569 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
570 build_terminate_handler ());
571 }
572
573 /* Let `cp_finish_decl' know that this initializer is ok. */
574 DECL_INITIAL (decl) = error_mark_node;
575 decl = pushdecl (decl);
576
577 start_decl_1 (decl);
578 cp_finish_decl (decl, init, NULL_TREE,
579 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
580 }
581
582 /* Call this to start a catch block. DECL is the catch parameter. */
583
584 tree
585 expand_start_catch_block (decl)
586 tree decl;
587 {
588 tree compound_stmt_1;
589 tree compound_stmt_2;
590 tree type;
591
592 if (! doing_eh (1))
593 return NULL_TREE;
594
595 /* Make sure this declaration is reasonable. */
596 if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
597 decl = NULL_TREE;
598
599 /* Create a binding level for the eh_info and the exception object
600 cleanup. */
601 compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
602
603 if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
604 {
605 /* The ordinary C++ case. */
606
607 if (decl)
608 type = build_eh_type_type_ref (TREE_TYPE (decl));
609 else
610 type = NULL_TREE;
611 begin_catch_block (type);
612
613 push_eh_info ();
614 push_eh_cleanup ();
615 }
616 else
617 {
618 /* The Java case. In this case, the match_info is a pointer to
619 the Java class object. We assume that the class is a
620 compiled class. */
621 tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
622 begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
623 }
624
625 /* Create a binding level for the parm. */
626 compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
627
628 if (decl)
629 initialize_handler_parm (decl);
630
631 return build_tree_list (compound_stmt_1, compound_stmt_2);
632 }
633
634
635 /* Call this to end a catch block. Its responsible for emitting the
636 code to handle jumping back to the correct place, and for emitting
637 the label to jump to if this catch block didn't match. */
638
639 void
640 expand_end_catch_block (blocks)
641 tree blocks;
642 {
643 tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
644 tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
645
646 if (! doing_eh (1))
647 return;
648
649 /* The exception being handled is rethrown if control reaches the end of
650 a handler of the function-try-block of a constructor or destructor. */
651 if (in_function_try_handler
652 && (DECL_CONSTRUCTOR_P (current_function_decl)
653 || DECL_DESTRUCTOR_P (current_function_decl)))
654 finish_expr_stmt (build_throw (NULL_TREE));
655
656 /* Cleanup the EH parameter. */
657 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
658 /* Cleanup the EH object. */
659 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
660 }
661
662 /* An exception spec is implemented more or less like:
663
664 try {
665 function body;
666 } catch (...) {
667 void *p[] = { typeid(raises) };
668 __check_eh_spec (p, count);
669 }
670
671 __check_eh_spec in exception.cc handles all the details. */
672
673 tree
674 expand_start_eh_spec ()
675 {
676 return begin_try_block ();
677 }
678
679 void
680 expand_end_eh_spec (raises, try_block)
681 tree raises;
682 tree try_block;
683 {
684 tree tmp, fn, decl, types = NULL_TREE;
685 tree blocks;
686 tree handler;
687 int count = 0;
688
689 finish_try_block (try_block);
690 handler = begin_handler ();
691 blocks = finish_handler_parms (NULL_TREE, handler);
692
693 /* Build up an array of type_infos. */
694 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
695 {
696 types = tree_cons
697 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
698 ++count;
699 }
700
701 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
702 TREE_HAS_CONSTRUCTOR (types) = 1;
703
704 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
705 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
706 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
707 DECL_ARTIFICIAL (decl) = 1;
708 DECL_INITIAL (decl) = types;
709 DECL_CONTEXT (decl) = current_function_decl;
710 cp_finish_decl (decl, types, NULL_TREE, 0);
711
712 decl = decay_conversion (decl);
713
714 fn = get_identifier ("__check_eh_spec");
715 if (IDENTIFIER_GLOBAL_VALUE (fn))
716 fn = IDENTIFIER_GLOBAL_VALUE (fn);
717 else
718 {
719 tmp = tree_cons
720 (NULL_TREE, integer_type_node, tree_cons
721 (NULL_TREE, TREE_TYPE (decl), void_list_node));
722
723 fn = push_throw_library_fn (fn, tmp);
724 }
725
726 tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
727 tree_cons (NULL_TREE, decl, NULL_TREE));
728 tmp = build_call (fn, tmp);
729 finish_expr_stmt (tmp);
730
731 finish_handler (blocks, handler);
732 finish_handler_sequence (try_block);
733 }
734
735 /* This is called to expand all the toplevel exception handling
736 finalization for a function. It should only be called once per
737 function. */
738
739 void
740 expand_exception_blocks ()
741 {
742 do_pending_stack_adjust ();
743
744 if (catch_clauses)
745 {
746 rtx funcend = gen_label_rtx ();
747 emit_jump (funcend);
748
749 /* We cannot protect n regions this way if we must flow into the
750 EH region through the top of the region, as we have to with
751 the setjmp/longjmp approach. */
752 if (exceptions_via_longjmp == 0)
753 expand_eh_region_start ();
754
755 emit_insns (catch_clauses);
756 catch_clauses = NULL_RTX;
757
758 if (exceptions_via_longjmp == 0)
759 expand_eh_region_end (build_terminate_handler ());
760
761 emit_insns (catch_clauses);
762 catch_clauses = NULL_RTX;
763 emit_label (funcend);
764 }
765 }
766
767 /* Return a pointer to a buffer for an exception object of type TYPE. */
768
769 static tree
770 alloc_eh_object (type)
771 tree type;
772 {
773 tree fn, exp;
774
775 fn = get_identifier ("__eh_alloc");
776 if (IDENTIFIER_GLOBAL_VALUE (fn))
777 fn = IDENTIFIER_GLOBAL_VALUE (fn);
778 else
779 {
780 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
781 tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
782 fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
783 }
784
785 exp = build_function_call (fn, tree_cons
786 (NULL_TREE, size_in_bytes (type), NULL_TREE));
787 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
788 return exp;
789 }
790
791 /* Expand a throw statement. This follows the following
792 algorithm:
793
794 1. Allocate space to save the current PC onto the stack.
795 2. Generate and emit a label and save its address into the
796 newly allocated stack space since we can't save the pc directly.
797 3. If this is the first call to throw in this function:
798 generate a label for the throw block
799 4. jump to the throw block label. */
800
801 static tree
802 expand_throw (exp)
803 tree exp;
804 {
805 tree fn;
806
807 if (! doing_eh (1))
808 return error_mark_node;
809
810 if (exp
811 && decl_is_java_type (TREE_TYPE (exp), 1))
812 {
813 /* A Java `throw' statement. */
814 tree args = tree_cons (NULL_TREE, exp, NULL);
815
816 fn = get_identifier (exceptions_via_longjmp
817 ? "_Jv_Sjlj_throw"
818 : "_Jv_Throw");
819 if (IDENTIFIER_GLOBAL_VALUE (fn))
820 fn = IDENTIFIER_GLOBAL_VALUE (fn);
821 else
822 {
823 /* Declare _Jv_Throw (void *), as defined in Java's
824 exception.cc. */
825 tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
826 tmp = build_function_type (ptr_type_node, tmp);
827 fn = push_library_fn (fn, tmp);
828 TREE_THIS_VOLATILE (fn) = 1;
829 TREE_NOTHROW (fn) = 0;
830 }
831
832 exp = build_function_call (fn, args);
833 }
834 else if (exp)
835 {
836 tree throw_type;
837 tree cleanup = NULL_TREE, e;
838 tree stmt_expr;
839 tree compound_stmt;
840 tree try_block;
841
842 begin_init_stmts (&stmt_expr, &compound_stmt);
843
844 /* throw expression */
845 /* First, decay it. */
846 exp = decay_conversion (exp);
847
848 /* cleanup_type is void (*)(void *, int),
849 the internal type of a destructor. */
850 if (cleanup_type == NULL_TREE)
851 cleanup_type = build_pointer_type
852 (build_function_type
853 (void_type_node, tree_cons
854 (NULL_TREE, ptr_type_node, tree_cons
855 (NULL_TREE, integer_type_node, void_list_node))));
856
857 if (TYPE_PTR_P (TREE_TYPE (exp)))
858 throw_type = build_eh_type_type (TREE_TYPE (exp));
859 else
860 {
861 tree object, ptr;
862
863 /* OK, this is kind of wacky. The standard says that we call
864 terminate when the exception handling mechanism, after
865 completing evaluation of the expression to be thrown but
866 before the exception is caught (_except.throw_), calls a
867 user function that exits via an uncaught exception.
868
869 So we have to protect the actual initialization of the
870 exception object with terminate(), but evaluate the expression
871 first. We also expand the call to __eh_alloc
872 first. Since there could be temps in the expression, we need
873 to handle that, too. */
874
875 my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
876
877 /* Store the throw expression into a temp. This can be less
878 efficient than storing it into the allocated space directly, but
879 oh well. To do this efficiently we would need to insinuate
880 ourselves into expand_call. */
881 if (TREE_SIDE_EFFECTS (exp))
882 {
883 tree temp = create_temporary_var (TREE_TYPE (exp));
884 DECL_INITIAL (temp) = exp;
885 cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
886 exp = temp;
887 }
888
889 /* Allocate the space for the exception. */
890 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
891 finish_expr_stmt (ptr);
892
893 try_block = begin_try_block ();
894 object = build_indirect_ref (ptr, NULL_PTR);
895 exp = build_modify_expr (object, INIT_EXPR, exp);
896
897 if (exp == error_mark_node)
898 error (" in thrown expression");
899
900 finish_expr_stmt (exp);
901 finish_cleanup_try_block (try_block);
902 finish_cleanup (build_terminate_handler (), try_block);
903
904 throw_type = build_eh_type_type (TREE_TYPE (object));
905
906 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
907 {
908 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
909 dtor_identifier, 0);
910 cleanup = TREE_VALUE (cleanup);
911 mark_used (cleanup);
912 mark_addressable (cleanup);
913 /* Pretend it's a normal function. */
914 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
915 }
916
917 exp = ptr;
918 }
919
920 /* Cast EXP to `void *' so that it will match the prototype for
921 __cp_push_exception. */
922 exp = convert (ptr_type_node, exp);
923
924 if (cleanup == NULL_TREE)
925 {
926 cleanup = build_int_2 (0, 0);
927 TREE_TYPE (cleanup) = cleanup_type;
928 }
929
930 fn = get_identifier ("__cp_push_exception");
931 if (IDENTIFIER_GLOBAL_VALUE (fn))
932 fn = IDENTIFIER_GLOBAL_VALUE (fn);
933 else
934 {
935 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
936 as defined in exception.cc. */
937 tree tmp;
938 tmp = tree_cons
939 (NULL_TREE, ptr_type_node, tree_cons
940 (NULL_TREE, ptr_type_node, tree_cons
941 (NULL_TREE, cleanup_type, void_list_node)));
942 fn = push_void_library_fn (fn, tmp);
943 }
944
945 e = tree_cons (NULL_TREE, exp, tree_cons
946 (NULL_TREE, throw_type, tree_cons
947 (NULL_TREE, cleanup, NULL_TREE)));
948 finish_expr_stmt (build_function_call (fn, e));
949
950 exp = finish_init_stmts (stmt_expr, compound_stmt);
951 }
952 else
953 {
954 /* rethrow current exception; note that it's no longer caught. */
955
956 tree fn = get_identifier ("__uncatch_exception");
957 if (IDENTIFIER_GLOBAL_VALUE (fn))
958 fn = IDENTIFIER_GLOBAL_VALUE (fn);
959 else
960 /* Declare void __uncatch_exception (void)
961 as defined in exception.cc. */
962 fn = push_void_library_fn (fn, void_list_node);
963
964 exp = build_function_call (fn, NULL_TREE);
965 }
966
967 return exp;
968 }
969
970 /* Build a throw expression. */
971
972 tree
973 build_throw (e)
974 tree e;
975 {
976 if (e == error_mark_node)
977 return e;
978
979 if (processing_template_decl)
980 return build_min (THROW_EXPR, void_type_node, e);
981
982 if (e == null_node)
983 cp_warning ("throwing NULL, which has integral, not pointer type");
984
985 if (e != NULL_TREE)
986 {
987 if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
988 return error_mark_node;
989 }
990
991 e = expand_throw (e);
992 e = build1 (THROW_EXPR, void_type_node, e);
993 TREE_SIDE_EFFECTS (e) = 1;
994 TREE_USED (e) = 1;
995
996 return e;
997 }
998
999 /* Make sure TYPE is complete, pointer to complete, reference to
1000 complete, or pointer to cv void. Issue diagnostic on failure.
1001 Return the zero on failure and non-zero on success. FROM can be
1002 the expr or decl from whence TYPE came, if available. */
1003
1004 static int
1005 complete_ptr_ref_or_void_ptr_p (type, from)
1006 tree type;
1007 tree from;
1008 {
1009 int is_ptr;
1010
1011 /* Check complete. */
1012 type = complete_type_or_else (type, from);
1013 if (!type)
1014 return 0;
1015
1016 /* Or a pointer or ref to one, or cv void *. */
1017 is_ptr = TREE_CODE (type) == POINTER_TYPE;
1018 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1019 {
1020 tree core = TREE_TYPE (type);
1021
1022 if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1023 /* OK */;
1024 else if (!complete_type_or_else (core, from))
1025 return 0;
1026 }
1027 return 1;
1028 }
1029
This page took 0.077483 seconds and 4 git commands to generate.