diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c index f2896c760f6..e320deadd8d 100644 --- a/contrib/gcc/cp/except.c +++ b/contrib/gcc/cp/except.c @@ -1,5 +1,6 @@ /* Handle exceptional things in C++. - Copyright (C) 1989, 92-97, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 Free Software Foundation, Inc. Contributed by Michael Tiemann Rewritten by Mike Stump , based upon an initial re-implementation courtesy Tad Hunt. @@ -28,681 +29,425 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "tree.h" #include "rtl.h" +#include "expr.h" +#include "libfuncs.h" #include "cp-tree.h" #include "flags.h" #include "obstack.h" -#include "expr.h" #include "output.h" #include "except.h" -#include "function.h" -#include "defaults.h" #include "toplev.h" -#include "eh-common.h" -rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); - -/* Holds the fndecl for __builtin_return_address. */ -tree builtin_return_address_fndecl; - -/* A couple of backend routines from m88k.c */ - -static void push_eh_cleanup PROTO((void)); -static tree build_eh_type_type PROTO((tree)); -static tree build_eh_type PROTO((tree)); -static void expand_end_eh_spec PROTO((tree)); -static tree call_eh_info PROTO((void)); -static void push_eh_info PROTO((void)); -static tree get_eh_info PROTO((void)); -static tree get_eh_value PROTO((void)); -#if 0 -static tree get_eh_type PROTO((void)); -static tree get_eh_caught PROTO((void)); -static tree get_eh_handlers PROTO((void)); -#endif -static tree do_pop_exception PROTO((void)); -static void process_start_catch_block PROTO((tree, tree)); -static tree build_eh_type_type_ref PROTO((tree)); -static tree build_terminate_handler PROTO((void)); -static tree alloc_eh_object PROTO((tree)); - -#if 0 -/* This is the startup, and finish stuff per exception table. */ - -/* XXX - Tad: exception handling section */ -#ifndef EXCEPT_SECTION_ASM_OP -#define EXCEPT_SECTION_ASM_OP "section\t.gcc_except_table,\"a\",@progbits" -#endif - -#ifdef EXCEPT_SECTION_ASM_OP - - /* on machines which support it, the exception table lives in another section, - but it needs a label so we can reference it... This sets up that - label! */ -asm (EXCEPT_SECTION_ASM_OP); -exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 }; -asm (TEXT_SECTION_ASM_OP); - -#endif /* EXCEPT_SECTION_ASM_OP */ - -#ifdef EXCEPT_SECTION_ASM_OP - - /* we need to know where the end of the exception table is... so this - is how we do it! */ - -asm (EXCEPT_SECTION_ASM_OP); -exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 }; -asm (TEXT_SECTION_ASM_OP); - -#endif /* EXCEPT_SECTION_ASM_OP */ - -#endif +static void push_eh_cleanup PARAMS ((tree)); +static tree prepare_eh_type PARAMS ((tree)); +static tree build_eh_type_type PARAMS ((tree)); +static tree do_begin_catch PARAMS ((void)); +static int dtor_nothrow PARAMS ((tree)); +static tree do_end_catch PARAMS ((tree)); +static void push_eh_cleanup PARAMS ((tree)); +static bool decl_is_java_type PARAMS ((tree decl, int err)); +static void initialize_handler_parm PARAMS ((tree, tree)); +static tree do_allocate_exception PARAMS ((tree)); +static int complete_ptr_ref_or_void_ptr_p PARAMS ((tree, tree)); +static bool is_admissible_throw_operand PARAMS ((tree)); +static int can_convert_eh PARAMS ((tree, tree)); +static void check_handlers_1 PARAMS ((tree, tree)); +static tree cp_protect_cleanup_actions PARAMS ((void)); #include "decl.h" -#include "insn-flags.h" #include "obstack.h" -/* ====================================================================== - Briefly the algorithm works like this: - - When a constructor or start of a try block is encountered, - push_eh_entry (&eh_stack) is called. Push_eh_entry () creates a - new entry in the unwind protection stack and returns a label to - output to start the protection for that block. - - When a destructor or end try block is encountered, pop_eh_entry - (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it - created when push_eh_entry () was called. The eh_entry structure - contains three things at this point. The start protect label, - the end protect label, and the exception handler label. The end - protect label should be output before the call to the destructor - (if any). If it was a destructor, then its parse tree is stored - in the finalization variable in the eh_entry structure. Otherwise - the finalization variable is set to NULL to reflect the fact that - it is the end of a try block. Next, this modified eh_entry node - is enqueued in the finalizations queue by calling - enqueue_eh_entry (&queue,entry). - - +---------------------------------------------------------------+ - |XXX: Will need modification to deal with partially | - | constructed arrays of objects | - | | - | Basically, this consists of keeping track of how many | - | of the objects have been constructed already (this | - | should be in a register though, so that shouldn't be a | - | problem. | - +---------------------------------------------------------------+ - - When a catch block is encountered, there is a lot of work to be - done. - - Since we don't want to generate the catch block inline with the - regular flow of the function, we need to have some way of doing - so. Luckily, we can use sequences to defer the catch sections. - When the start of a catch block is encountered, we start the - sequence. After the catch block is generated, we end the - sequence. - - Next we must insure that when the catch block is executed, all - finalizations for the matching try block have been completed. If - any of those finalizations throw an exception, we must call - terminate according to the ARM (section r.15.6.1). What this - means is that we need to dequeue and emit finalizations for each - entry in the eh_queue until we get to an entry with a NULL - finalization field. For any of the finalization entries, if it - is not a call to terminate (), we must protect it by giving it - another start label, end label, and exception handler label, - setting its finalization tree to be a call to terminate (), and - enqueue'ing this new eh_entry to be output at an outer level. - Finally, after all that is done, we can get around to outputting - the catch block which basically wraps all the "catch (...) {...}" - statements in a big if/then/else construct that matches the - correct block to call. - - ===================================================================== */ - -/* local globals for function calls - ====================================================================== */ - -/* Used to cache "terminate" and "__throw_type_match*". */ -static tree Terminate, CatchMatch; - -/* Used to cache __find_first_exception_table_match for throw. */ -static tree FirstExceptionMatch; - -/* Used to cache a call to __unwind_function. */ -static tree Unwind; - -/* ====================================================================== */ - - -/* ========================================================================= */ - - - -/* local globals - these local globals are for storing data necessary for - generating the exception table and code in the correct order. - - ========================================================================= */ - -extern rtx catch_clauses; -extern tree const_ptr_type_node; - -/* ========================================================================= */ - -/* sets up all the global eh stuff that needs to be initialized at the - start of compilation. - - This includes: - - Setting up all the function call trees. */ +/* Sets up all the global eh stuff that needs to be initialized at the + start of compilation. */ void init_exception_processing () { - /* void vtype () */ - tree vtype = build_function_type (void_type_node, void_list_node); - - if (flag_honor_std) - push_namespace (get_identifier ("std")); - Terminate = auto_function (get_identifier ("terminate"), - vtype, NOT_BUILT_IN); - TREE_THIS_VOLATILE (Terminate) = 1; - if (flag_honor_std) - pop_namespace (); + tree tmp; - push_lang_context (lang_name_c); + /* void std::terminate (); */ + push_namespace (std_identifier); + tmp = build_function_type (void_type_node, void_list_node); + terminate_node = build_cp_library_fn_ptr ("terminate", tmp); + TREE_THIS_VOLATILE (terminate_node) = 1; + TREE_NOTHROW (terminate_node) = 1; + pop_namespace (); - set_exception_lang_code (EH_LANG_C_plus_plus); - set_exception_version_code (1); + /* void __cxa_call_unexpected(void *); */ + tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); + tmp = build_function_type (void_type_node, tmp); + call_unexpected_node + = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); - CatchMatch - = builtin_function (flag_rtti - ? "__throw_type_match_rtti" - : "__throw_type_match", - build_function_type (ptr_type_node, - tree_cons (NULL_TREE, const_ptr_type_node, - tree_cons (NULL_TREE, const_ptr_type_node, - tree_cons (NULL_TREE, ptr_type_node, - void_list_node)))), - NOT_BUILT_IN, NULL_PTR); - FirstExceptionMatch - = builtin_function ("__find_first_exception_table_match", - build_function_type (ptr_type_node, - tree_cons (NULL_TREE, ptr_type_node, - void_list_node)), - NOT_BUILT_IN, NULL_PTR); - Unwind - = builtin_function ("__unwind_function", - build_function_type (void_type_node, - tree_cons (NULL_TREE, ptr_type_node, - void_list_node)), - NOT_BUILT_IN, NULL_PTR); + eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS + ? "__gxx_personality_sj0" + : "__gxx_personality_v0"); - pop_lang_context (); - - /* If we use setjmp/longjmp EH, arrange for all cleanup actions to - be protected with __terminate. */ - protect_cleanup_actions_with_terminate = 1; + lang_eh_runtime_type = build_eh_type_type; + lang_protect_cleanup_actions = &cp_protect_cleanup_actions; } -/* Retrieve a pointer to the cp_eh_info node for the current exception. */ +/* Returns an expression to be executed if an unhandled exception is + propagated out of a cleanup region. */ static tree -call_eh_info () +cp_protect_cleanup_actions () { - tree fn; + /* [except.terminate] - fn = get_identifier ("__start_cp_handler"); - if (IDENTIFIER_GLOBAL_VALUE (fn)) - fn = IDENTIFIER_GLOBAL_VALUE (fn); - else - { - tree t1, t, fields[7]; - - /* Declare cp_eh_info * __start_cp_handler (void), - as defined in exception.cc. */ - push_obstacks_nochange (); - end_temporary_allocation (); - - /* struct cp_eh_info. This must match exception.cc. Note that this - type is not pushed anywhere. */ - t1= make_lang_type (RECORD_TYPE); - fields[0] = build_lang_field_decl (FIELD_DECL, - get_identifier ("handler_label"), ptr_type_node); - fields[1] = build_lang_field_decl (FIELD_DECL, - get_identifier ("dynamic_handler_chain"), ptr_type_node); - fields[2] = build_lang_field_decl (FIELD_DECL, - get_identifier ("info"), ptr_type_node); - fields[3] = build_lang_field_decl (FIELD_DECL, - get_identifier ("table_index"), ptr_type_node); - /* N.B.: The fourth field LEN is expected to be - the number of fields - 1, not the total number of fields. */ - finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node); - t1 = build_pointer_type (t1); - - t1= make_lang_type (RECORD_TYPE); - fields[0] = build_lang_field_decl (FIELD_DECL, - get_identifier ("match_function"), ptr_type_node); - fields[1] = build_lang_field_decl (FIELD_DECL, - get_identifier ("language"), short_integer_type_node); - fields[2] = build_lang_field_decl (FIELD_DECL, - get_identifier ("version"), short_integer_type_node); - /* N.B.: The fourth field LEN is expected to be - the number of fields - 1, not the total number of fields. */ - finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node); - t = make_lang_type (RECORD_TYPE); - fields[0] = build_lang_field_decl (FIELD_DECL, - get_identifier ("eh_info"), t1); - fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"), - ptr_type_node); - fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"), - ptr_type_node); - fields[3] = build_lang_field_decl - (FIELD_DECL, get_identifier ("cleanup"), - build_pointer_type (build_function_type - (ptr_type_node, tree_cons - (NULL_TREE, ptr_type_node, void_list_node)))); - fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"), - boolean_type_node); - fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"), - build_pointer_type (t)); - fields[6] = build_lang_field_decl - (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node); - /* N.B.: The fourth field LEN is expected to be - the number of fields - 1, not the total number of fields. */ - finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node); - t = build_pointer_type (t); - - /* And now the function. */ - fn = build_lang_decl (FUNCTION_DECL, fn, - build_function_type (t, void_list_node)); - DECL_EXTERNAL (fn) = 1; - TREE_PUBLIC (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - pushdecl_top_level (fn); - make_function_rtl (fn); - pop_obstacks (); - } - mark_used (fn); - return build_function_call (fn, NULL_TREE); -} - -/* Retrieve a pointer to the cp_eh_info node for the current exception - and save it in the current binding level. */ - -static void -push_eh_info () -{ - tree decl, fn = call_eh_info (); - - /* Remember the pointer to the current exception info; it won't change - during this catch block. */ - decl = build_decl (VAR_DECL, get_identifier ("__exception_info"), - TREE_TYPE (fn)); - DECL_ARTIFICIAL (decl) = 1; - DECL_INITIAL (decl) = fn; - decl = pushdecl (decl); - cp_finish_decl (decl, fn, NULL_TREE, 0, 0); -} - -/* Returns a reference to the cp_eh_info node for the current exception. */ + When the destruction of an object during stack unwinding exits + using an exception ... void terminate(); is called. */ + return build_call (terminate_node, NULL_TREE); +} static tree -get_eh_info () +prepare_eh_type (type) + tree type; { - /* Look for the pointer pushed in push_eh_info. */ - tree t = lookup_name (get_identifier ("__exception_info"), 0); - return build_indirect_ref (t, NULL_PTR); + if (type == NULL_TREE) + return type; + if (type == error_mark_node) + return error_mark_node; + + /* peel back references, so they match. */ + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + /* Peel off cv qualifiers. */ + type = TYPE_MAIN_VARIANT (type); + + return type; } -/* Returns a reference to the current exception object. */ - -static tree -get_eh_value () -{ - return build_component_ref (get_eh_info (), get_identifier ("value"), - NULL_TREE, 0); -} - -/* Returns a reference to the current exception type. */ - -#if 0 -static tree -get_eh_type () -{ - return build_component_ref (get_eh_info (), get_identifier ("type"), - NULL_TREE, 0); -} - -/* Returns a reference to whether or not the current exception - has been caught. */ - -static tree -get_eh_caught () -{ - return build_component_ref (get_eh_info (), get_identifier ("caught"), - NULL_TREE, 0); -} - -/* Returns a reference to whether or not the current exception - has been caught. */ - -static tree -get_eh_handlers () -{ - return build_component_ref (get_eh_info (), get_identifier ("handlers"), - NULL_TREE, 0); -} -#endif - -/* Build a type value for use at runtime for a type that is matched - against by the exception handling system. */ +/* Build the address of a typeinfo decl for use in the runtime + matching field of the exception model. */ static tree build_eh_type_type (type) tree type; { - const char *typestring; tree exp; - if (type == error_mark_node) - return error_mark_node; + if (type == NULL_TREE || type == error_mark_node) + return type; - /* peel back references, so they match. */ - if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); - - /* Peel off cv qualifiers. */ - type = TYPE_MAIN_VARIANT (type); - - if (flag_rtti) - return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type)); - - typestring = build_overload_name (type, 1, 1); - exp = combine_strings (build_string (strlen (typestring)+1, typestring)); - return build1 (ADDR_EXPR, ptr_type_node, exp); -} - -/* Build the address of a runtime type for use in the runtime matching - field of the new exception model */ - -static tree -build_eh_type_type_ref (type) - tree type; -{ - const char *typestring; - tree exp; - - if (type == error_mark_node) - return error_mark_node; - - /* peel back references, so they match. */ - if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); - - /* Peel off cv qualifiers. */ - type = TYPE_MAIN_VARIANT (type); - - push_obstacks_nochange (); - end_temporary_allocation (); - - if (flag_rtti) - { - exp = get_tinfo_fn (type); - TREE_USED (exp) = 1; - mark_inline_for_output (exp); - exp = build1 (ADDR_EXPR, ptr_type_node, exp); - } + if (decl_is_java_type (type, 0)) + exp = build_java_class_ref (TREE_TYPE (type)); else - { - typestring = build_overload_name (type, 1, 1); - exp = combine_strings (build_string (strlen (typestring)+1, typestring)); - exp = build1 (ADDR_EXPR, ptr_type_node, exp); - } - pop_obstacks (); - return (exp); + exp = get_tinfo_decl (type); + + mark_used (exp); + exp = build1 (ADDR_EXPR, ptr_type_node, exp); + + return exp; } +tree +build_exc_ptr () +{ + return build (EXC_PTR_EXPR, ptr_type_node); +} -/* Build a type value for use at runtime for a exp that is thrown or - matched against by the exception handling system. */ +/* Build up a call to __cxa_begin_catch, to tell the runtime that the + exception has been handled. */ static tree -build_eh_type (exp) - tree exp; +do_begin_catch () { - if (flag_rtti) - { - exp = build_typeid (exp); - return build1 (ADDR_EXPR, ptr_type_node, exp); - } - return build_eh_type_type (TREE_TYPE (exp)); -} + tree fn; -/* This routine is called to mark all the symbols representing runtime - type functions in the exception table as haveing been referenced. - This will make sure code is emitted for them. Called from finish_file. */ -void -mark_all_runtime_matches () -{ - int x,num; - void **ptr; - tree exp; - - num = find_all_handler_type_matches (&ptr); - if (num == 0 || ptr == NULL) - return; - - for (x=0; x