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.
8 This file is part of GNU CC.
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)
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.
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. */
38 #include "eh-common.h"
40 static void push_eh_cleanup PARAMS ((tree));
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));
47 static tree get_eh_type PARAMS ((void));
48 static tree get_eh_caught PARAMS ((void));
49 static tree get_eh_handlers PARAMS ((void));
51 static int dtor_nothrow PARAMS ((tree));
52 static tree do_pop_exception PARAMS ((tree));
53 static tree build_eh_type_type_ref PARAMS ((tree));
54 static tree build_terminate_handler PARAMS ((void));
55 static tree alloc_eh_object PARAMS ((tree));
56 static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree));
57 static void initialize_handler_parm PARAMS ((tree));
58 static tree expand_throw PARAMS ((tree));
59 static int decl_is_java_type PARAMS ((tree decl, int err));
62 /* This is the startup, and finish stuff per exception table. */
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"
69 #ifdef EXCEPT_SECTION_ASM_OP
71 /* on machines which support it, the exception table lives in another section,
72 but it needs a label so we can reference it... This sets up that
74 asm (EXCEPT_SECTION_ASM_OP);
75 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
76 asm (TEXT_SECTION_ASM_OP);
78 #endif /* EXCEPT_SECTION_ASM_OP */
80 #ifdef EXCEPT_SECTION_ASM_OP
82 /* we need to know where the end of the exception table is... so this
85 asm (EXCEPT_SECTION_ASM_OP);
86 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
87 asm (TEXT_SECTION_ASM_OP);
89 #endif /* EXCEPT_SECTION_ASM_OP */
94 #include "insn-flags.h"
97 /* In a given translation unit we are constrained to catch only C++
98 types or only Java types. `catch_language' holds the current type,
99 and `catch_language_init' registers whether `catch_language' has
102 static int catch_language_init = 0;
103 static int catch_language;
105 /* ======================================================================
106 Briefly the algorithm works like this:
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.
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 it is 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).
126 +---------------------------------------------------------------+
127 |XXX: Will need modification to deal with partially |
128 | constructed arrays of objects |
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 |
134 +---------------------------------------------------------------+
136 When a catch block is encountered, there is a lot of work to be
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
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.
162 ===================================================================== */
164 /* ====================================================================== */
166 /* sets up all the global eh stuff that needs to be initialized at the
167 start of compilation. */
170 init_exception_processing ()
173 tree vtype = build_function_type (void_type_node, void_list_node);
176 push_namespace (get_identifier ("std"));
177 terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
178 TREE_THIS_VOLATILE (terminate_node) = 1;
179 TREE_NOTHROW (terminate_node) = 1;
183 set_exception_lang_code (EH_LANG_C_plus_plus);
184 set_exception_version_code (1);
186 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
187 be protected with __terminate. */
188 protect_cleanup_actions_with_terminate = 1;
191 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
198 fn = get_identifier ("__start_cp_handler");
199 if (IDENTIFIER_GLOBAL_VALUE (fn))
200 fn = IDENTIFIER_GLOBAL_VALUE (fn);
203 tree t1, t, fields[7];
205 /* Declare cp_eh_info * __start_cp_handler (void),
206 as defined in exception.cc. */
208 /* struct cp_eh_info. This must match exception.cc. Note that this
209 type is not pushed anywhere. */
210 t1= make_aggr_type (RECORD_TYPE);
211 fields[0] = build_lang_decl (FIELD_DECL,
212 get_identifier ("handler_label"), ptr_type_node);
213 fields[1] = build_lang_decl (FIELD_DECL,
214 get_identifier ("dynamic_handler_chain"), ptr_type_node);
215 fields[2] = build_lang_decl (FIELD_DECL,
216 get_identifier ("info"), ptr_type_node);
217 fields[3] = build_lang_decl (FIELD_DECL,
218 get_identifier ("table_index"), ptr_type_node);
219 /* N.B.: The fourth field LEN is expected to be
220 the number of fields - 1, not the total number of fields. */
221 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
222 t1 = build_pointer_type (t1);
224 t1= make_aggr_type (RECORD_TYPE);
225 fields[0] = build_lang_decl (FIELD_DECL,
226 get_identifier ("match_function"), ptr_type_node);
227 fields[1] = build_lang_decl (FIELD_DECL,
228 get_identifier ("language"), short_integer_type_node);
229 fields[2] = build_lang_decl (FIELD_DECL,
230 get_identifier ("version"), short_integer_type_node);
231 /* N.B.: The fourth field LEN is expected to be
232 the number of fields - 1, not the total number of fields. */
233 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
234 t = make_aggr_type (RECORD_TYPE);
235 fields[0] = build_lang_decl (FIELD_DECL,
236 get_identifier ("eh_info"), t1);
237 fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
239 fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
241 fields[3] = build_lang_decl
242 (FIELD_DECL, get_identifier ("cleanup"),
243 build_pointer_type (build_function_type
244 (ptr_type_node, tree_cons
245 (NULL_TREE, ptr_type_node, void_list_node))));
246 fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
248 fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
249 build_pointer_type (t));
250 fields[6] = build_lang_decl
251 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
252 /* N.B.: The fourth field LEN is expected to be
253 the number of fields - 1, not the total number of fields. */
254 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
255 t = build_pointer_type (t);
257 /* And now the function. */
258 fn = push_library_fn (fn, build_function_type (t, void_list_node));
260 return build_function_call (fn, NULL_TREE);
263 /* Retrieve a pointer to the cp_eh_info node for the current exception
264 and save it in the current binding level. */
269 tree decl, fn = call_eh_info ();
271 /* Remember the pointer to the current exception info; it won't change
272 during this catch block. */
273 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
275 DECL_ARTIFICIAL (decl) = 1;
276 DECL_INITIAL (decl) = fn;
277 decl = pushdecl (decl);
278 cp_finish_decl (decl, fn, NULL_TREE, 0);
281 /* Returns a reference to the cp_eh_info node for the current exception. */
286 /* Look for the pointer pushed in push_eh_info. */
287 tree t = lookup_name (get_identifier ("__exception_info"), 0);
288 return build_indirect_ref (t, NULL_PTR);
291 /* Returns a reference to the current exception object. */
296 return build_component_ref (get_eh_info (), get_identifier ("value"),
300 /* Returns a reference to the current exception type. */
306 return build_component_ref (get_eh_info (), get_identifier ("type"),
310 /* Returns a reference to whether or not the current exception
316 return build_component_ref (get_eh_info (), get_identifier ("caught"),
320 /* Returns a reference to whether or not the current exception
326 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
331 /* Build a type value for use at runtime for a type that is matched
332 against by the exception handling system. */
335 build_eh_type_type (type)
338 if (type == error_mark_node)
339 return error_mark_node;
341 /* peel back references, so they match. */
342 if (TREE_CODE (type) == REFERENCE_TYPE)
343 type = TREE_TYPE (type);
345 /* Peel off cv qualifiers. */
346 type = TYPE_MAIN_VARIANT (type);
348 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
351 /* Build the address of a typeinfo decl for use in the runtime
352 matching field of the new exception model */
355 build_eh_type_type_ref (type)
360 if (type == NULL_TREE || type == error_mark_node)
363 /* peel back references, so they match. */
364 if (TREE_CODE (type) == REFERENCE_TYPE)
365 type = TREE_TYPE (type);
367 /* Peel off cv qualifiers. */
368 type = TYPE_MAIN_VARIANT (type);
370 exp = get_tinfo_decl (type);
372 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
377 /* This routine is called to mark all the symbols representing runtime
378 type functions in the exception table as having been referenced.
379 This will make sure code is emitted for them. Called from finish_file. */
382 mark_all_runtime_matches ()
388 num = find_all_handler_type_matches (&ptr);
389 if (num == 0 || ptr == NULL)
392 for (x=0; x <num; x++)
395 if (TREE_CODE (exp) == ADDR_EXPR)
397 exp = TREE_OPERAND (exp, 0);
398 if (TREE_CODE (exp) == FUNCTION_DECL)
399 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
406 /* Returns nonzero if cleaning up an exception of type TYPE (which can be
407 NULL_TREE for a ... handler) will not throw an exception. */
415 if (type == NULL_TREE)
418 if (! TYPE_HAS_DESTRUCTOR (type))
421 fn = lookup_member (type, dtor_identifier, 0, 0);
422 fn = TREE_VALUE (fn);
423 return TREE_NOTHROW (fn);
426 /* Build up a call to __cp_pop_exception, to destroy the exception object
427 for the current catch block if no others are currently using it. */
430 do_pop_exception (type)
434 fn = get_identifier ("__cp_pop_exception");
435 if (IDENTIFIER_GLOBAL_VALUE (fn))
436 fn = IDENTIFIER_GLOBAL_VALUE (fn);
439 /* Declare void __cp_pop_exception (void *),
440 as defined in exception.cc. */
441 fn = push_void_library_fn
442 (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
443 /* This can throw if the destructor for the exception throws. */
444 TREE_NOTHROW (fn) = 0;
447 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
448 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
449 cleanup = build_function_call (fn, tree_cons
450 (NULL_TREE, cleanup, NULL_TREE));
451 TREE_NOTHROW (cleanup) = dtor_nothrow (type);
455 /* This routine creates the cleanup for the current exception. */
458 push_eh_cleanup (type)
461 finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
464 /* Build up a call to terminate on the function obstack, for use as an
465 exception handler. */
468 build_terminate_handler ()
470 return build_function_call (terminate_node, NULL_TREE);
473 /* Return nonzero value if DECL is a Java type suitable for catch or
477 decl_is_java_type (decl, err)
481 int r = (TREE_CODE (decl) == POINTER_TYPE
482 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
483 && TYPE_FOR_JAVA (TREE_TYPE (decl)));
487 if (TREE_CODE (decl) == REFERENCE_TYPE
488 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
489 && TYPE_FOR_JAVA (TREE_TYPE (decl)))
491 /* Can't throw a reference. */
492 cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
499 = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
500 if (jthrow_node == NULL_TREE)
501 fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
502 jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
504 if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
506 /* Thrown object must be a Throwable. */
507 cp_error ("type `%T' is not derived from `java::lang::Throwable'",
516 /* Initialize the catch parameter DECL. */
519 initialize_handler_parm (decl)
527 /* Make sure we mark the catch param as used, otherwise we'll get a
528 warning about an unused ((anonymous)). */
529 TREE_USED (decl) = 1;
531 /* Figure out the type that the initializer is. */
532 init_type = TREE_TYPE (decl);
533 if (TREE_CODE (init_type) != REFERENCE_TYPE
534 && TREE_CODE (init_type) != POINTER_TYPE)
535 init_type = build_reference_type (init_type);
537 if (decl_is_java_type (init_type, 0))
540 = builtin_function ("_Jv_exception_info",
541 build_function_type (ptr_type_node,
542 tree_cons (NULL_TREE,
545 0, NOT_BUILT_IN, NULL_PTR);
547 exp = build (CALL_EXPR, ptr_type_node,
548 build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
550 NULL_TREE, NULL_TREE);
551 TREE_SIDE_EFFECTS (exp) = 1;
554 set_exception_lang_code (EH_LANG_Java);
555 set_exception_version_code (1);
559 exp = get_eh_value ();
560 lang = EH_LANG_C_plus_plus;
563 if (catch_language_init)
565 if (lang != catch_language)
566 error ("mixing C++ and Java `catch'es in single translation unit");
570 catch_language_init = 1;
571 catch_language = lang;
574 /* Since pointers are passed by value, initialize a reference to
575 pointer catch parm with the address of the value slot. */
576 if (TREE_CODE (init_type) == REFERENCE_TYPE
577 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
578 exp = build_unary_op (ADDR_EXPR, exp, 1);
580 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
582 init = convert_from_reference (exp);
584 /* If the constructor for the catch parm exits via an exception, we
585 must call terminate. See eh23.C. */
586 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
588 /* Generate the copy constructor call directly so we can wrap it.
589 See also expand_default_init. */
590 init = ocp_convert (TREE_TYPE (decl), init,
591 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
592 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
593 build_terminate_handler ());
596 /* Let `cp_finish_decl' know that this initializer is ok. */
597 DECL_INITIAL (decl) = error_mark_node;
598 decl = pushdecl (decl);
601 cp_finish_decl (decl, init, NULL_TREE,
602 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
605 /* Call this to start a catch block. DECL is the catch parameter. */
608 expand_start_catch_block (decl)
611 tree compound_stmt_1;
612 tree compound_stmt_2;
617 /* Make sure this declaration is reasonable. */
618 if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
621 /* Create a binding level for the eh_info and the exception object
623 compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
625 if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
627 /* The ordinary C++ case. */
631 type = TREE_TYPE (decl);
634 begin_catch_block (build_eh_type_type_ref (type));
637 push_eh_cleanup (type);
641 /* The Java case. In this case, the match_info is a pointer to
642 the Java class object. We assume that the class is a
644 tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
645 begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
648 /* Create a binding level for the parm. */
649 compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
652 initialize_handler_parm (decl);
654 return build_tree_list (compound_stmt_1, compound_stmt_2);
658 /* Call this to end a catch block. Its responsible for emitting the
659 code to handle jumping back to the correct place, and for emitting
660 the label to jump to if this catch block didn't match. */
663 expand_end_catch_block (blocks)
666 tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
667 tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
672 /* The exception being handled is rethrown if control reaches the end of
673 a handler of the function-try-block of a constructor or destructor. */
674 if (in_function_try_handler
675 && (DECL_CONSTRUCTOR_P (current_function_decl)
676 || DECL_DESTRUCTOR_P (current_function_decl)))
677 finish_expr_stmt (build_throw (NULL_TREE));
679 /* Cleanup the EH parameter. */
680 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
681 /* Cleanup the EH object. */
682 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
685 /* An exception spec is implemented more or less like:
690 void *p[] = { typeid(raises) };
691 __check_eh_spec (p, count);
694 __check_eh_spec in exception.cc handles all the details. */
697 expand_start_eh_spec ()
699 return begin_try_block ();
703 expand_end_eh_spec (raises, try_block)
707 tree tmp, fn, decl, types = NULL_TREE;
712 finish_try_block (try_block);
713 handler = begin_handler ();
714 blocks = finish_handler_parms (NULL_TREE, handler);
716 if (TREE_VALUE (raises) == NULL_TREE)
718 fn = get_identifier ("__check_null_eh_spec");
719 if (IDENTIFIER_GLOBAL_VALUE (fn))
720 fn = IDENTIFIER_GLOBAL_VALUE (fn);
723 tmp = build_function_type (void_type_node, void_list_node);
724 fn = push_throw_library_fn (fn, tmp);
725 /* Since the spec doesn't allow any exceptions, this call
727 TREE_NOTHROW (fn) = 1;
733 /* Build up an array of type_infos. */
734 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
737 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
741 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
742 TREE_HAS_CONSTRUCTOR (types) = 1;
744 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
745 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
746 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
747 DECL_ARTIFICIAL (decl) = 1;
748 DECL_INITIAL (decl) = types;
749 DECL_CONTEXT (decl) = current_function_decl;
750 cp_finish_decl (decl, types, NULL_TREE, 0);
752 decl = decay_conversion (decl);
754 fn = get_identifier ("__check_eh_spec");
755 if (IDENTIFIER_GLOBAL_VALUE (fn))
756 fn = IDENTIFIER_GLOBAL_VALUE (fn);
760 (NULL_TREE, integer_type_node, tree_cons
761 (NULL_TREE, TREE_TYPE (decl), void_list_node));
762 tmp = build_function_type (void_type_node, tmp);
764 fn = push_throw_library_fn (fn, tmp);
767 tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
768 tree_cons (NULL_TREE, decl, NULL_TREE));
771 tmp = build_call (fn, tmp);
772 finish_expr_stmt (tmp);
774 finish_handler (blocks, handler);
775 finish_handler_sequence (try_block);
778 /* This is called to expand all the toplevel exception handling
779 finalization for a function. It should only be called once per
783 expand_exception_blocks ()
785 do_pending_stack_adjust ();
789 rtx funcend = gen_label_rtx ();
792 /* We cannot protect n regions this way if we must flow into the
793 EH region through the top of the region, as we have to with
794 the setjmp/longjmp approach. */
795 if (exceptions_via_longjmp == 0)
796 expand_eh_region_start ();
798 emit_insns (catch_clauses);
799 catch_clauses = NULL_RTX;
801 if (exceptions_via_longjmp == 0)
802 expand_eh_region_end (build_terminate_handler ());
804 emit_insns (catch_clauses);
805 catch_clauses = NULL_RTX;
806 emit_label (funcend);
810 /* Return a pointer to a buffer for an exception object of type TYPE. */
813 alloc_eh_object (type)
818 fn = get_identifier ("__eh_alloc");
819 if (IDENTIFIER_GLOBAL_VALUE (fn))
820 fn = IDENTIFIER_GLOBAL_VALUE (fn);
823 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
824 tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
825 fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
828 exp = build_function_call (fn, tree_cons
829 (NULL_TREE, size_in_bytes (type), NULL_TREE));
830 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
834 /* Expand a throw statement. This follows the following
837 1. Allocate space to save the current PC onto the stack.
838 2. Generate and emit a label and save its address into the
839 newly allocated stack space since we can't save the pc directly.
840 3. If this is the first call to throw in this function:
841 generate a label for the throw block
842 4. jump to the throw block label. */
851 return error_mark_node;
854 && decl_is_java_type (TREE_TYPE (exp), 1))
856 /* A Java `throw' statement. */
857 tree args = tree_cons (NULL_TREE, exp, NULL);
859 fn = get_identifier (exceptions_via_longjmp
862 if (IDENTIFIER_GLOBAL_VALUE (fn))
863 fn = IDENTIFIER_GLOBAL_VALUE (fn);
866 /* Declare _Jv_Throw (void *), as defined in Java's
868 tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
869 tmp = build_function_type (ptr_type_node, tmp);
870 fn = push_library_fn (fn, tmp);
871 TREE_THIS_VOLATILE (fn) = 1;
872 TREE_NOTHROW (fn) = 0;
875 exp = build_function_call (fn, args);
880 tree cleanup = NULL_TREE, e;
885 begin_init_stmts (&stmt_expr, &compound_stmt);
887 /* throw expression */
888 /* First, decay it. */
889 exp = decay_conversion (exp);
891 /* cleanup_type is void (*)(void *, int),
892 the internal type of a destructor. */
893 if (cleanup_type == NULL_TREE)
894 cleanup_type = build_pointer_type
896 (void_type_node, tree_cons
897 (NULL_TREE, ptr_type_node, tree_cons
898 (NULL_TREE, integer_type_node, void_list_node))));
900 if (TYPE_PTR_P (TREE_TYPE (exp)))
901 throw_type = build_eh_type_type (TREE_TYPE (exp));
906 /* OK, this is kind of wacky. The standard says that we call
907 terminate when the exception handling mechanism, after
908 completing evaluation of the expression to be thrown but
909 before the exception is caught (_except.throw_), calls a
910 user function that exits via an uncaught exception.
912 So we have to protect the actual initialization of the
913 exception object with terminate(), but evaluate the expression
914 first. We also expand the call to __eh_alloc
915 first. Since there could be temps in the expression, we need
916 to handle that, too. */
918 my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
920 /* Store the throw expression into a temp. This can be less
921 efficient than storing it into the allocated space directly, but
922 oh well. To do this efficiently we would need to insinuate
923 ourselves into expand_call. */
924 if (TREE_SIDE_EFFECTS (exp))
926 tree temp = create_temporary_var (TREE_TYPE (exp));
927 DECL_INITIAL (temp) = exp;
928 cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
932 /* Allocate the space for the exception. */
933 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
934 finish_expr_stmt (ptr);
936 try_block = begin_try_block ();
937 object = build_indirect_ref (ptr, NULL_PTR);
938 exp = build_modify_expr (object, INIT_EXPR, exp);
940 if (exp == error_mark_node)
941 error (" in thrown expression");
943 finish_expr_stmt (exp);
944 finish_cleanup_try_block (try_block);
945 finish_cleanup (build_terminate_handler (), try_block);
947 throw_type = build_eh_type_type (TREE_TYPE (object));
949 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
951 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
953 cleanup = TREE_VALUE (cleanup);
955 mark_addressable (cleanup);
956 /* Pretend it's a normal function. */
957 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
963 /* Cast EXP to `void *' so that it will match the prototype for
964 __cp_push_exception. */
965 exp = convert (ptr_type_node, exp);
967 if (cleanup == NULL_TREE)
969 cleanup = build_int_2 (0, 0);
970 TREE_TYPE (cleanup) = cleanup_type;
973 fn = get_identifier ("__cp_push_exception");
974 if (IDENTIFIER_GLOBAL_VALUE (fn))
975 fn = IDENTIFIER_GLOBAL_VALUE (fn);
978 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
979 as defined in exception.cc. */
982 (NULL_TREE, ptr_type_node, tree_cons
983 (NULL_TREE, ptr_type_node, tree_cons
984 (NULL_TREE, cleanup_type, void_list_node)));
985 fn = push_void_library_fn (fn, tmp);
988 e = tree_cons (NULL_TREE, exp, tree_cons
989 (NULL_TREE, throw_type, tree_cons
990 (NULL_TREE, cleanup, NULL_TREE)));
991 finish_expr_stmt (build_function_call (fn, e));
993 exp = finish_init_stmts (stmt_expr, compound_stmt);
997 /* rethrow current exception; note that it's no longer caught. */
999 tree fn = get_identifier ("__uncatch_exception");
1000 if (IDENTIFIER_GLOBAL_VALUE (fn))
1001 fn = IDENTIFIER_GLOBAL_VALUE (fn);
1003 /* Declare void __uncatch_exception (void)
1004 as defined in exception.cc. */
1005 fn = push_void_library_fn (fn, void_list_node);
1007 exp = build_function_call (fn, NULL_TREE);
1013 /* Build a throw expression. */
1019 if (e == error_mark_node)
1022 if (processing_template_decl)
1023 return build_min (THROW_EXPR, void_type_node, e);
1026 cp_warning ("throwing NULL, which has integral, not pointer type");
1030 if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1031 return error_mark_node;
1034 e = expand_throw (e);
1035 e = build1 (THROW_EXPR, void_type_node, e);
1036 TREE_SIDE_EFFECTS (e) = 1;
1042 /* Make sure TYPE is complete, pointer to complete, reference to
1043 complete, or pointer to cv void. Issue diagnostic on failure.
1044 Return the zero on failure and non-zero on success. FROM can be
1045 the expr or decl from whence TYPE came, if available. */
1048 complete_ptr_ref_or_void_ptr_p (type, from)
1054 /* Check complete. */
1055 type = complete_type_or_else (type, from);
1059 /* Or a pointer or ref to one, or cv void *. */
1060 is_ptr = TREE_CODE (type) == POINTER_TYPE;
1061 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1063 tree core = TREE_TYPE (type);
1065 if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1067 else if (!complete_type_or_else (core, from))
1073 /* Returns nonzero if FN is a declaration of a standard C library
1074 function which is known not to throw.
1076 [lib.res.on.exception.handling]: None of the functions from the
1077 Standard C library shall report an error by throwing an
1078 exception, unless it calls a program-supplied function that
1079 throws an exception. */
1084 nothrow_libfn_p (fn)
1089 if (TREE_PUBLIC (fn)
1090 && DECL_EXTERNAL (fn)
1091 && DECL_LANGUAGE (fn) == lang_c)
1094 /* Can't be a C library function. */
1097 id = DECL_ASSEMBLER_NAME (fn);
1098 return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));