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 ((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));
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 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));
61 /* This is the startup, and finish stuff per exception table. */
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"
68 #ifdef EXCEPT_SECTION_ASM_OP
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
73 asm (EXCEPT_SECTION_ASM_OP);
74 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
75 asm (TEXT_SECTION_ASM_OP);
77 #endif /* EXCEPT_SECTION_ASM_OP */
79 #ifdef EXCEPT_SECTION_ASM_OP
81 /* we need to know where the end of the exception table is... so this
84 asm (EXCEPT_SECTION_ASM_OP);
85 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
86 asm (TEXT_SECTION_ASM_OP);
88 #endif /* EXCEPT_SECTION_ASM_OP */
93 #include "insn-flags.h"
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
101 static int catch_language_init = 0;
102 static int catch_language;
104 /* ======================================================================
105 Briefly the algorithm works like this:
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.
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).
125 +---------------------------------------------------------------+
126 |XXX: Will need modification to deal with partially |
127 | constructed arrays of objects |
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 |
133 +---------------------------------------------------------------+
135 When a catch block is encountered, there is a lot of work to be
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
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.
161 ===================================================================== */
163 /* ====================================================================== */
165 /* sets up all the global eh stuff that needs to be initialized at the
166 start of compilation. */
169 init_exception_processing ()
172 tree vtype = build_function_type (void_type_node, void_list_node);
175 push_namespace (get_identifier ("std"));
176 terminate_node = auto_function (get_identifier ("terminate"), vtype);
177 TREE_THIS_VOLATILE (terminate_node) = 1;
181 set_exception_lang_code (EH_LANG_C_plus_plus);
182 set_exception_version_code (1);
184 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
185 be protected with __terminate. */
186 protect_cleanup_actions_with_terminate = 1;
189 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
196 fn = get_identifier ("__start_cp_handler");
197 if (IDENTIFIER_GLOBAL_VALUE (fn))
198 fn = IDENTIFIER_GLOBAL_VALUE (fn);
201 tree t1, t, fields[7];
203 /* Declare cp_eh_info * __start_cp_handler (void),
204 as defined in exception.cc. */
206 /* struct cp_eh_info. This must match exception.cc. Note that this
207 type is not pushed anywhere. */
208 t1= make_aggr_type (RECORD_TYPE);
209 fields[0] = build_lang_decl (FIELD_DECL,
210 get_identifier ("handler_label"), ptr_type_node);
211 fields[1] = build_lang_decl (FIELD_DECL,
212 get_identifier ("dynamic_handler_chain"), ptr_type_node);
213 fields[2] = build_lang_decl (FIELD_DECL,
214 get_identifier ("info"), ptr_type_node);
215 fields[3] = build_lang_decl (FIELD_DECL,
216 get_identifier ("table_index"), ptr_type_node);
217 /* N.B.: The fourth field LEN is expected to be
218 the number of fields - 1, not the total number of fields. */
219 finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
220 t1 = build_pointer_type (t1);
222 t1= make_aggr_type (RECORD_TYPE);
223 fields[0] = build_lang_decl (FIELD_DECL,
224 get_identifier ("match_function"), ptr_type_node);
225 fields[1] = build_lang_decl (FIELD_DECL,
226 get_identifier ("language"), short_integer_type_node);
227 fields[2] = build_lang_decl (FIELD_DECL,
228 get_identifier ("version"), short_integer_type_node);
229 /* N.B.: The fourth field LEN is expected to be
230 the number of fields - 1, not the total number of fields. */
231 finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
232 t = make_aggr_type (RECORD_TYPE);
233 fields[0] = build_lang_decl (FIELD_DECL,
234 get_identifier ("eh_info"), t1);
235 fields[1] = build_lang_decl (FIELD_DECL, get_identifier ("value"),
237 fields[2] = build_lang_decl (FIELD_DECL, get_identifier ("type"),
239 fields[3] = build_lang_decl
240 (FIELD_DECL, get_identifier ("cleanup"),
241 build_pointer_type (build_function_type
242 (ptr_type_node, tree_cons
243 (NULL_TREE, ptr_type_node, void_list_node))));
244 fields[4] = build_lang_decl (FIELD_DECL, get_identifier ("caught"),
246 fields[5] = build_lang_decl (FIELD_DECL, get_identifier ("next"),
247 build_pointer_type (t));
248 fields[6] = build_lang_decl
249 (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
250 /* N.B.: The fourth field LEN is expected to be
251 the number of fields - 1, not the total number of fields. */
252 finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
253 t = build_pointer_type (t);
255 /* And now the function. */
256 fn = build_lang_decl (FUNCTION_DECL, fn,
257 build_function_type (t, void_list_node));
258 DECL_EXTERNAL (fn) = 1;
259 TREE_PUBLIC (fn) = 1;
260 DECL_ARTIFICIAL (fn) = 1;
261 TREE_NOTHROW (fn) = 1;
262 pushdecl_top_level (fn);
263 make_function_rtl (fn);
266 return build_function_call (fn, NULL_TREE);
269 /* Retrieve a pointer to the cp_eh_info node for the current exception
270 and save it in the current binding level. */
275 tree decl, fn = call_eh_info ();
277 /* Remember the pointer to the current exception info; it won't change
278 during this catch block. */
279 decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
281 DECL_ARTIFICIAL (decl) = 1;
282 DECL_INITIAL (decl) = fn;
283 decl = pushdecl (decl);
284 cp_finish_decl (decl, fn, NULL_TREE, 0);
287 /* Returns a reference to the cp_eh_info node for the current exception. */
292 /* Look for the pointer pushed in push_eh_info. */
293 tree t = lookup_name (get_identifier ("__exception_info"), 0);
294 return build_indirect_ref (t, NULL_PTR);
297 /* Returns a reference to the current exception object. */
302 return build_component_ref (get_eh_info (), get_identifier ("value"),
306 /* Returns a reference to the current exception type. */
312 return build_component_ref (get_eh_info (), get_identifier ("type"),
316 /* Returns a reference to whether or not the current exception
322 return build_component_ref (get_eh_info (), get_identifier ("caught"),
326 /* Returns a reference to whether or not the current exception
332 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
337 /* Build a type value for use at runtime for a type that is matched
338 against by the exception handling system. */
341 build_eh_type_type (type)
344 if (type == error_mark_node)
345 return error_mark_node;
347 /* peel back references, so they match. */
348 if (TREE_CODE (type) == REFERENCE_TYPE)
349 type = TREE_TYPE (type);
351 /* Peel off cv qualifiers. */
352 type = TYPE_MAIN_VARIANT (type);
354 return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
357 /* Build the address of a typeinfo decl for use in the runtime
358 matching field of the new exception model */
361 build_eh_type_type_ref (type)
366 if (type == error_mark_node)
367 return error_mark_node;
369 /* peel back references, so they match. */
370 if (TREE_CODE (type) == REFERENCE_TYPE)
371 type = TREE_TYPE (type);
373 /* Peel off cv qualifiers. */
374 type = TYPE_MAIN_VARIANT (type);
376 exp = get_tinfo_decl (type);
378 exp = build1 (ADDR_EXPR, ptr_type_node, exp);
383 /* This routine is called to mark all the symbols representing runtime
384 type functions in the exception table as having been referenced.
385 This will make sure code is emitted for them. Called from finish_file. */
387 mark_all_runtime_matches ()
393 num = find_all_handler_type_matches (&ptr);
394 if (num == 0 || ptr == NULL)
397 for (x=0; x <num; x++)
400 if (TREE_CODE (exp) == ADDR_EXPR)
402 exp = TREE_OPERAND (exp, 0);
403 if (TREE_CODE (exp) == FUNCTION_DECL)
404 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
411 /* Build up a call to __cp_pop_exception, to destroy the exception object
412 for the current catch block. HANDLER is either true or false, telling
413 the library whether or not it is being called from an exception handler;
414 if it is, it avoids destroying the object on rethrow. */
420 fn = get_identifier ("__cp_pop_exception");
421 if (IDENTIFIER_GLOBAL_VALUE (fn))
422 fn = IDENTIFIER_GLOBAL_VALUE (fn);
425 /* Declare void __cp_pop_exception (void *),
426 as defined in exception.cc. */
429 build_function_type (void_type_node, tree_cons
430 (NULL_TREE, ptr_type_node, void_list_node)));
431 DECL_EXTERNAL (fn) = 1;
432 TREE_PUBLIC (fn) = 1;
433 DECL_ARTIFICIAL (fn) = 1;
434 pushdecl_top_level (fn);
435 make_function_rtl (fn);
439 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
440 cleanup = lookup_name (get_identifier ("__exception_info"), 0);
441 cleanup = build_function_call (fn, tree_cons
442 (NULL_TREE, cleanup, NULL_TREE));
446 /* This routine creates the cleanup for the current exception. */
451 finish_decl_cleanup (NULL_TREE, do_pop_exception ());
454 /* Build up a call to terminate on the function obstack, for use as an
455 exception handler. */
458 build_terminate_handler ()
460 return build_function_call (terminate_node, NULL_TREE);
463 /* Return nonzero value if DECL is a Java type suitable for catch or
467 decl_is_java_type (decl, err)
471 int r = (TREE_CODE (decl) == POINTER_TYPE
472 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
473 && TYPE_FOR_JAVA (TREE_TYPE (decl)));
477 if (TREE_CODE (decl) == REFERENCE_TYPE
478 && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
479 && TYPE_FOR_JAVA (TREE_TYPE (decl)))
481 /* Can't throw a reference. */
482 cp_error ("type `%T' is disallowed in Java `throw' or `catch'",
489 = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jthrowable"));
490 if (jthrow_node == NULL_TREE)
491 fatal ("call to Java `catch' or `throw', while `jthrowable' undefined");
492 jthrow_node = TREE_TYPE (TREE_TYPE (jthrow_node));
494 if (! DERIVED_FROM_P (jthrow_node, TREE_TYPE (decl)))
496 /* Thrown object must be a Throwable. */
497 cp_error ("type `%T' is not derived from `java::lang::Throwable'",
506 /* Initialize the catch parameter DECL. */
509 initialize_handler_parm (decl)
517 /* Make sure we mark the catch param as used, otherwise we'll get a
518 warning about an unused ((anonymous)). */
519 TREE_USED (decl) = 1;
521 /* Figure out the type that the initializer is. */
522 init_type = TREE_TYPE (decl);
523 if (TREE_CODE (init_type) != REFERENCE_TYPE
524 && TREE_CODE (init_type) != POINTER_TYPE)
525 init_type = build_reference_type (init_type);
527 if (decl_is_java_type (init_type, 0))
530 = builtin_function ("_Jv_exception_info",
531 build_function_type (ptr_type_node,
532 tree_cons (NULL_TREE,
535 0, NOT_BUILT_IN, NULL_PTR);
537 exp = build (CALL_EXPR, ptr_type_node,
538 build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
540 NULL_TREE, NULL_TREE);
541 TREE_SIDE_EFFECTS (exp) = 1;
544 set_exception_lang_code (EH_LANG_Java);
545 set_exception_version_code (1);
549 exp = get_eh_value ();
550 lang = EH_LANG_C_plus_plus;
553 if (catch_language_init)
555 if (lang != catch_language)
556 error ("mixing C++ and Java `catch'es in single translation unit");
560 catch_language_init = 1;
561 catch_language = lang;
564 /* Since pointers are passed by value, initialize a reference to
565 pointer catch parm with the address of the value slot. */
566 if (TREE_CODE (init_type) == REFERENCE_TYPE
567 && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
568 exp = build_unary_op (ADDR_EXPR, exp, 1);
570 exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
572 init = convert_from_reference (exp);
574 /* If the constructor for the catch parm exits via an exception, we
575 must call terminate. See eh23.C. */
576 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
578 /* Generate the copy constructor call directly so we can wrap it.
579 See also expand_default_init. */
580 init = ocp_convert (TREE_TYPE (decl), init,
581 CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
582 init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
583 build_terminate_handler ());
586 /* Let `cp_finish_decl' know that this initializer is ok. */
587 DECL_INITIAL (decl) = error_mark_node;
588 decl = pushdecl (decl);
591 cp_finish_decl (decl, init, NULL_TREE,
592 LOOKUP_ONLYCONVERTING|DIRECT_BIND);
595 /* Call this to start a catch block. DECL is the catch parameter. */
598 expand_start_catch_block (decl)
601 tree compound_stmt_1;
602 tree compound_stmt_2;
608 /* Make sure this declaration is reasonable. */
609 if (decl && !complete_ptr_ref_or_void_ptr_p (TREE_TYPE (decl), NULL_TREE))
612 /* Create a binding level for the eh_info and the exception object
614 compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
616 if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
618 /* The ordinary C++ case. */
621 type = build_eh_type_type_ref (TREE_TYPE (decl));
624 begin_catch_block (type);
631 /* The Java case. In this case, the match_info is a pointer to
632 the Java class object. We assume that the class is a
634 tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
635 begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
638 /* Create a binding level for the parm. */
639 compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
642 initialize_handler_parm (decl);
644 return build_tree_list (compound_stmt_1, compound_stmt_2);
648 /* Call this to end a catch block. Its responsible for emitting the
649 code to handle jumping back to the correct place, and for emitting
650 the label to jump to if this catch block didn't match. */
653 expand_end_catch_block (blocks)
656 tree compound_stmt_1 = blocks ? TREE_PURPOSE (blocks): NULL_TREE;
657 tree compound_stmt_2 = blocks ? TREE_VALUE (blocks): NULL_TREE;
662 /* The exception being handled is rethrown if control reaches the end of
663 a handler of the function-try-block of a constructor or destructor. */
664 if (in_function_try_handler
665 && (DECL_CONSTRUCTOR_P (current_function_decl)
666 || DECL_DESTRUCTOR_P (current_function_decl)))
667 finish_expr_stmt (build_throw (NULL_TREE));
669 /* Cleanup the EH parameter. */
670 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
671 /* Cleanup the EH object. */
672 finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
675 /* An exception spec is implemented more or less like:
680 void *p[] = { typeid(raises) };
681 __check_eh_spec (p, count);
684 __check_eh_spec in exception.cc handles all the details. */
687 expand_start_eh_spec ()
689 return begin_try_block ();
693 expand_end_eh_spec (raises, try_block)
697 tree tmp, fn, decl, types = NULL_TREE;
702 finish_try_block (try_block);
703 handler = begin_handler ();
704 blocks = finish_handler_parms (NULL_TREE, handler);
706 /* Build up an array of type_infos. */
707 for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
710 (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
714 types = build_nt (CONSTRUCTOR, NULL_TREE, types);
715 TREE_HAS_CONSTRUCTOR (types) = 1;
717 /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
718 tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
719 decl = build_decl (VAR_DECL, NULL_TREE, tmp);
720 DECL_ARTIFICIAL (decl) = 1;
721 DECL_INITIAL (decl) = types;
722 DECL_CONTEXT (decl) = current_function_decl;
723 cp_finish_decl (decl, types, NULL_TREE, 0);
725 decl = decay_conversion (decl);
727 fn = get_identifier ("__check_eh_spec");
728 if (IDENTIFIER_GLOBAL_VALUE (fn))
729 fn = IDENTIFIER_GLOBAL_VALUE (fn);
733 (NULL_TREE, integer_type_node, tree_cons
734 (NULL_TREE, TREE_TYPE (decl), void_list_node));
735 tmp = build_function_type (void_type_node, tmp);
737 fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
738 DECL_EXTERNAL (fn) = 1;
739 TREE_PUBLIC (fn) = 1;
740 DECL_ARTIFICIAL (fn) = 1;
741 TREE_THIS_VOLATILE (fn) = 1;
742 pushdecl_top_level (fn);
743 make_function_rtl (fn);
747 tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
748 tree_cons (NULL_TREE, decl, NULL_TREE));
749 tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
750 finish_expr_stmt (tmp);
752 finish_handler (blocks, handler);
753 finish_handler_sequence (try_block);
756 /* This is called to expand all the toplevel exception handling
757 finalization for a function. It should only be called once per
761 expand_exception_blocks ()
763 do_pending_stack_adjust ();
767 rtx funcend = gen_label_rtx ();
770 /* We cannot protect n regions this way if we must flow into the
771 EH region through the top of the region, as we have to with
772 the setjmp/longjmp approach. */
773 if (exceptions_via_longjmp == 0)
774 expand_eh_region_start ();
776 emit_insns (catch_clauses);
777 catch_clauses = NULL_RTX;
779 if (exceptions_via_longjmp == 0)
780 expand_eh_region_end (build_terminate_handler ());
782 emit_insns (catch_clauses);
783 catch_clauses = NULL_RTX;
784 emit_label (funcend);
788 /* Return a pointer to a buffer for an exception object of type TYPE. */
791 alloc_eh_object (type)
796 fn = get_identifier ("__eh_alloc");
797 if (IDENTIFIER_GLOBAL_VALUE (fn))
798 fn = IDENTIFIER_GLOBAL_VALUE (fn);
801 /* Declare __eh_alloc (size_t), as defined in exception.cc. */
803 tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
804 fn = build_lang_decl (FUNCTION_DECL, fn,
805 build_function_type (ptr_type_node, tmp));
806 DECL_EXTERNAL (fn) = 1;
807 TREE_PUBLIC (fn) = 1;
808 DECL_ARTIFICIAL (fn) = 1;
809 TREE_NOTHROW (fn) = 1;
810 pushdecl_top_level (fn);
811 make_function_rtl (fn);
815 exp = build_function_call (fn, tree_cons
816 (NULL_TREE, size_in_bytes (type), NULL_TREE));
817 exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
821 /* Expand a throw statement. This follows the following
824 1. Allocate space to save the current PC onto the stack.
825 2. Generate and emit a label and save its address into the
826 newly allocated stack space since we can't save the pc directly.
827 3. If this is the first call to throw in this function:
828 generate a label for the throw block
829 4. jump to the throw block label. */
838 return error_mark_node;
841 && decl_is_java_type (TREE_TYPE (exp), 1))
843 /* A Java `throw' statement. */
844 tree args = tree_cons (NULL_TREE, exp, NULL);
846 fn = get_identifier (exceptions_via_longjmp
849 if (IDENTIFIER_GLOBAL_VALUE (fn))
850 fn = IDENTIFIER_GLOBAL_VALUE (fn);
853 /* Declare _Jv_Throw (void *), as defined in Java's
856 tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
857 fn = build_lang_decl (FUNCTION_DECL, fn,
858 build_function_type (ptr_type_node, tmp));
859 DECL_EXTERNAL (fn) = 1;
860 TREE_PUBLIC (fn) = 1;
861 DECL_ARTIFICIAL (fn) = 1;
862 TREE_THIS_VOLATILE (fn) = 1;
863 pushdecl_top_level (fn);
864 make_function_rtl (fn);
867 exp = build_function_call (fn, args);
872 tree cleanup = NULL_TREE, e;
877 begin_init_stmts (&stmt_expr, &compound_stmt);
879 /* throw expression */
880 /* First, decay it. */
881 exp = decay_conversion (exp);
883 /* cleanup_type is void (*)(void *, int),
884 the internal type of a destructor. */
885 if (cleanup_type == NULL_TREE)
886 cleanup_type = build_pointer_type
888 (void_type_node, tree_cons
889 (NULL_TREE, ptr_type_node, tree_cons
890 (NULL_TREE, integer_type_node, void_list_node))));
892 if (TYPE_PTR_P (TREE_TYPE (exp)))
893 throw_type = build_eh_type_type (TREE_TYPE (exp));
898 /* OK, this is kind of wacky. The standard says that we call
899 terminate when the exception handling mechanism, after
900 completing evaluation of the expression to be thrown but
901 before the exception is caught (_except.throw_), calls a
902 user function that exits via an uncaught exception.
904 So we have to protect the actual initialization of the
905 exception object with terminate(), but evaluate the expression
906 first. We also expand the call to __eh_alloc
907 first. Since there could be temps in the expression, we need
908 to handle that, too. */
910 my_friendly_assert (stmts_are_full_exprs_p == 1, 19990926);
912 /* Store the throw expression into a temp. This can be less
913 efficient than storing it into the allocated space directly, but
914 oh well. To do this efficiently we would need to insinuate
915 ourselves into expand_call. */
916 if (TREE_SIDE_EFFECTS (exp))
918 tree temp = create_temporary_var (TREE_TYPE (exp));
919 DECL_INITIAL (temp) = exp;
920 cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
924 /* Allocate the space for the exception. */
925 ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
926 finish_expr_stmt (ptr);
928 try_block = begin_try_block ();
929 object = build_indirect_ref (ptr, NULL_PTR);
930 exp = build_modify_expr (object, INIT_EXPR, exp);
932 if (exp == error_mark_node)
933 error (" in thrown expression");
935 finish_expr_stmt (exp);
936 finish_cleanup_try_block (try_block);
937 finish_cleanup (build_terminate_handler (), try_block);
939 throw_type = build_eh_type_type (TREE_TYPE (object));
941 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
943 cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
945 cleanup = TREE_VALUE (cleanup);
947 mark_addressable (cleanup);
948 /* Pretend it's a normal function. */
949 cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
955 /* Cast EXP to `void *' so that it will match the prototype for
956 __cp_push_exception. */
957 exp = convert (ptr_type_node, exp);
959 if (cleanup == NULL_TREE)
961 cleanup = build_int_2 (0, 0);
962 TREE_TYPE (cleanup) = cleanup_type;
965 fn = get_identifier ("__cp_push_exception");
966 if (IDENTIFIER_GLOBAL_VALUE (fn))
967 fn = IDENTIFIER_GLOBAL_VALUE (fn);
970 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
971 as defined in exception.cc. */
974 (NULL_TREE, ptr_type_node, tree_cons
975 (NULL_TREE, ptr_type_node, tree_cons
976 (NULL_TREE, cleanup_type, void_list_node)));
977 fn = build_lang_decl (FUNCTION_DECL, fn,
978 build_function_type (void_type_node, tmp));
979 DECL_EXTERNAL (fn) = 1;
980 TREE_PUBLIC (fn) = 1;
981 DECL_ARTIFICIAL (fn) = 1;
982 TREE_NOTHROW (fn) = 1;
983 pushdecl_top_level (fn);
984 make_function_rtl (fn);
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);
1004 /* Declare void __uncatch_exception (void)
1005 as defined in exception.cc. */
1006 fn = build_lang_decl (FUNCTION_DECL, fn,
1007 build_function_type (void_type_node,
1009 DECL_EXTERNAL (fn) = 1;
1010 TREE_PUBLIC (fn) = 1;
1011 DECL_ARTIFICIAL (fn) = 1;
1012 TREE_NOTHROW (fn) = 1;
1013 pushdecl_top_level (fn);
1014 make_function_rtl (fn);
1018 exp = build_function_call (fn, NULL_TREE);
1024 /* Build a throw expression. */
1030 if (e == error_mark_node)
1033 if (processing_template_decl)
1034 return build_min (THROW_EXPR, void_type_node, e);
1037 cp_warning ("throwing NULL, which has integral, not pointer type");
1041 if (!complete_ptr_ref_or_void_ptr_p (TREE_TYPE (e), e))
1042 return error_mark_node;
1045 e = expand_throw (e);
1046 e = build1 (THROW_EXPR, void_type_node, e);
1047 TREE_SIDE_EFFECTS (e) = 1;
1053 /* Make sure TYPE is complete, pointer to complete, reference to
1054 complete, or pointer to cv void. Issue diagnostic on failure.
1055 Return the zero on failure and non-zero on success. FROM can be
1056 the expr or decl from whence TYPE came, if available. */
1059 complete_ptr_ref_or_void_ptr_p (type, from)
1065 /* Check complete. */
1066 type = complete_type_or_else (type, from);
1070 /* Or a pointer or ref to one, or cv void *. */
1071 is_ptr = TREE_CODE (type) == POINTER_TYPE;
1072 if (is_ptr || TREE_CODE (type) == REFERENCE_TYPE)
1074 tree core = TREE_TYPE (type);
1076 if (is_ptr && same_type_p (TYPE_MAIN_VARIANT (core), void_type_node))
1078 else if (!complete_type_or_else (core, from))