This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ia64 eh, part 20b [c++]
- To: gcc-patches at gcc dot gnu dot org
- Subject: ia64 eh, part 20b [c++]
- From: Richard Henderson <rth at redhat dot com>
- Date: Wed, 28 Mar 2001 01:52:19 -0800
This is the C++ front end change. With the exception of the
Java bits in cp/except.c, it is basically unchanged from the
last time Jason reviewed it.
r~
IA-64 ABI Exception Handling:
* cp-tree.def (EH_SPEC_BLOCK): New.
(MUST_NOT_THROW_EXPR): New.
* cp-tree.h: Update changed function declarations.
(CPTI_PUSH_EXCEPTION_IDENTIFIER): Remove.
(CPTI_CALL_UNEXPECTED): New.
(struct cp_language_function): Rename x_eh_spec_try_block
to x_eh_spec_block.
(EH_SPEC_STMTS, EH_SPEC_RAISES): New.
* decl.c (current_binding_level): If no current function
bindings, revert to scope_chain.
(initialize_predefined_identifiers): Remove __cp_push_exception.
(store_parm_decls): Use begin_eh_spec_block.
(finish_function): Use finish_eh_spec_block.
(mark_lang_function): Update for name changes.
* decl2.c (finish_file): No mark_all_runtime_matches.
* dump.c (cp_dump_tree): Handle new tree codes.
* error.c (dump_expr) [BIND_EXPR]: Fix typo.
* except.c (catch_language_init, catch_language): Remove.
(init_exception_processing): Don't set language code.
Initialize call_unexpected_node, protect_cleanup_actions,
eh_personality_libfunc, lang_eh_runtime_type.
(call_eh_info, push_eh_info, get_eh_info, get_eh_value): Remove.
(get_eh_type, get_eh_caught, get_eh_handlers): Remove.
(prepare_eh_type): Split out type canonicalizations ...
(build_eh_type_type): ... from here.
(build_eh_type_type_ref): Remove.
(mark_all_runtime_matches): Remove.
(build_exc_ptr): New.
(do_begin_catch, do_end_catch): New.
(do_pop_exception): Remove.
(build_terminate_handler): Remove.
(choose_personality_routine): Split out language choice from ...
(initialize_handler_parm): ... here.
Use MUST_NOT_THROW_EXPR.
(expand_start_catch_block): Use do_begin_catch. Simplify Java
exception object handling.
(expand_start_eh_spec, expand_end_eh_spec): Remove.
(expand_exception_blocks, alloc_eh_object): Remove.
(begin_eh_spec_block, finish_eh_spec_block): New.
(do_allocate_exception, do_free_exception): New.
(expand_throw): Merge into ...
(build_throw): ... here. Update for abi.
* expr.c (cplus_expand_expr): No expand_internal_throw.
Handle MUST_NOT_THROW_EXPR.
* pt.c (tsubst_expr): Handle EH_SPEC_BLOCK.
* semantics.c (*) Update for except.h name changes.
(genrtl_try_block): No protect_with_terminate.
(genrtl_eh_spec_block): New.
(genrtl_handler): Don't emit the goto here.
(cp_expand_stmt): Handle EH_SPEC_BLOCK.
(genrtl_finish_function): Don't expand_exception_blocks.
* tree.c (cp_statement_code_p): Handle EH_SPEC_BLOCK.
Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.54
diff -c -p -d -r1.54 cp-tree.def
*** cp-tree.def 2001/01/05 11:41:27 1.54
--- cp-tree.def 2001/03/28 09:49:49
*************** DEFTREECODE (START_CATCH_STMT, "start_ca
*** 236,242 ****
--- 236,247 ----
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
+ DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
DEFTREECODE (HANDLER, "handler", 'e', 2)
+
+ /* A MUST_NOT_THROW_EXPR wraps an expression that may not
+ throw, and must call terminate if it does. */
+ DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", 'e', 1)
DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.591
diff -c -p -d -r1.591 cp-tree.h
*** cp-tree.h 2001/03/28 08:25:45 1.591
--- cp-tree.h 2001/03/28 09:49:49
*************** enum cp_tree_index
*** 616,622 ****
CPTI_PFN_IDENTIFIER,
CPTI_PFN_OR_DELTA2_IDENTIFIER,
CPTI_VPTR_IDENTIFIER,
- CPTI_PUSH_EXCEPTION_IDENTIFIER,
CPTI_STD_IDENTIFIER,
CPTI_LANG_NAME_C,
--- 616,621 ----
*************** enum cp_tree_index
*** 627,632 ****
--- 626,632 ----
CPTI_NULL,
CPTI_JCLASS,
CPTI_TERMINATE,
+ CPTI_CALL_UNEXPECTED,
CPTI_ATEXIT,
CPTI_DSO_HANDLE,
CPTI_DCAST,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 740,748 ****
#define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER]
#define pfn_or_delta2_identifier cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
- /* The name of the function to call to push an exception onto the
- exception stack. */
- #define cp_push_exception_identifier cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
/* The name of the std namespace. */
#define std_identifier cp_global_trees[CPTI_STD_IDENTIFIER]
#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
--- 740,745 ----
*************** extern tree cp_global_trees[CPTI_MAX];
*** 761,766 ****
--- 758,766 ----
/* The declaration for `std::terminate'. */
#define terminate_node cp_global_trees[CPTI_TERMINATE]
+ /* The declaration for "__cxa_call_unexpected". */
+ #define call_unexpected_node cp_global_trees[CPTI_CALL_UNEXPECTED]
+
/* A pointer to `std::atexit'. */
#define atexit_node cp_global_trees[CPTI_ATEXIT]
*************** struct cp_language_function
*** 872,878 ****
tree x_dtor_label;
tree x_current_class_ptr;
tree x_current_class_ref;
! tree x_eh_spec_try_block;
tree x_in_charge_parm;
tree x_vtt_parm;
--- 872,878 ----
tree x_dtor_label;
tree x_current_class_ptr;
tree x_current_class_ref;
! tree x_eh_spec_block;
tree x_in_charge_parm;
tree x_vtt_parm;
*************** struct cp_language_function
*** 916,925 ****
#define current_class_ref \
(cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
! /* The TRY_BLOCK for the exception-specifiers for the current
function, if any. */
! #define current_eh_spec_try_block cp_function_chain->x_eh_spec_try_block
/* The `__in_chrg' parameter for the current function. Only used for
constructors and destructors. */
--- 916,925 ----
#define current_class_ref \
(cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
! /* The EH_SPEC_BLOCK for the exception-specifiers for the current
function, if any. */
! #define current_eh_spec_block cp_function_chain->x_eh_spec_block
/* The `__in_chrg' parameter for the current function. Only used for
constructors and destructors. */
*************** extern int flag_new_for_scope;
*** 3035,3040 ****
--- 3035,3043 ----
#define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
#define TRY_HANDLERS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 1)
+ #define EH_SPEC_STMTS(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 0)
+ #define EH_SPEC_RAISES(NODE) TREE_OPERAND (EH_SPEC_BLOCK_CHECK (NODE), 1)
+
/* Nonzero if this try block is a function try block. */
#define FN_TRY_BLOCK_P(NODE) TREE_LANG_FLAG_3 (TRY_BLOCK_CHECK (NODE))
#define HANDLER_PARMS(NODE) TREE_OPERAND (HANDLER_CHECK (NODE), 0)
*************** extern void init_exception_processing P
*** 4000,4008 ****
extern tree expand_start_catch_block PARAMS ((tree));
extern void expand_end_catch_block PARAMS ((tree));
extern void expand_builtin_throw PARAMS ((void));
! extern tree expand_start_eh_spec PARAMS ((void));
! extern void expand_end_eh_spec PARAMS ((tree, tree));
extern void expand_exception_blocks PARAMS ((void));
extern tree build_throw PARAMS ((tree));
extern void mark_all_runtime_matches PARAMS ((void));
extern int nothrow_libfn_p PARAMS ((tree));
--- 4003,4011 ----
extern tree expand_start_catch_block PARAMS ((tree));
extern void expand_end_catch_block PARAMS ((tree));
extern void expand_builtin_throw PARAMS ((void));
! extern void expand_eh_spec_block PARAMS ((tree));
extern void expand_exception_blocks PARAMS ((void));
+ extern tree build_exc_ptr PARAMS ((void));
extern tree build_throw PARAMS ((tree));
extern void mark_all_runtime_matches PARAMS ((void));
extern int nothrow_libfn_p PARAMS ((tree));
*************** extern tree finish_case_label
*** 4256,4261 ****
--- 4259,4266 ----
extern tree finish_goto_stmt PARAMS ((tree));
extern tree begin_try_block PARAMS ((void));
extern void finish_try_block PARAMS ((tree));
+ extern tree begin_eh_spec_block PARAMS ((void));
+ extern void finish_eh_spec_block PARAMS ((tree, tree));
extern void finish_handler_sequence PARAMS ((tree));
extern tree begin_function_try_block PARAMS ((void));
extern void finish_function_try_block PARAMS ((tree));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.766
diff -c -p -d -r1.766 decl.c
*** decl.c 2001/03/28 08:25:45 1.766
--- decl.c 2001/03/28 09:49:49
*************** struct binding_level
*** 478,484 ****
/* The binding level currently in effect. */
#define current_binding_level \
! (cfun \
? cp_function_chain->bindings \
: scope_chain->bindings)
--- 478,484 ----
/* The binding level currently in effect. */
#define current_binding_level \
! (cfun && cp_function_chain->bindings \
? cp_function_chain->bindings \
: scope_chain->bindings)
*************** initialize_predefined_identifiers ()
*** 6306,6312 ****
{ VTABLE_PFN_NAME, &pfn_identifier, 0 },
{ "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
{ "_vptr", &vptr_identifier, 0 },
- { "__cp_push_exception", &cp_push_exception_identifier, 0 },
{ "__vtt_parm", &vtt_parm_identifier, 0 },
{ "std", &std_identifier, 0 },
{ NULL, NULL, 0 }
--- 6306,6311 ----
*************** store_parm_decls (current_function_parms
*** 13721,13727 ****
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! current_eh_spec_try_block = expand_start_eh_spec ();
}
--- 13720,13726 ----
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! current_eh_spec_block = begin_eh_spec_block ();
}
*************** finish_function (flags)
*** 13966,13974 ****
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS
! (TREE_TYPE (current_function_decl)),
! current_eh_spec_try_block);
}
/* If we're saving up tree structure, tie off the function now. */
--- 13965,13973 ----
if (flag_exceptions && !processing_template_decl
&& flag_enforce_eh_specs
&& TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
! finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS
! (TREE_TYPE (current_function_decl)),
! current_eh_spec_block);
}
/* If we're saving up tree structure, tie off the function now. */
*************** mark_lang_function (p)
*** 14395,14401 ****
ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_current_class_ptr);
ggc_mark_tree (p->x_current_class_ref);
! ggc_mark_tree (p->x_eh_spec_try_block);
ggc_mark_tree_varray (p->x_local_names);
mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
--- 14394,14400 ----
ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_current_class_ptr);
ggc_mark_tree (p->x_current_class_ref);
! ggc_mark_tree (p->x_eh_spec_block);
ggc_mark_tree_varray (p->x_local_names);
mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.448
diff -c -p -d -r1.448 decl2.c
*** decl2.c 2001/03/22 00:55:11 1.448
--- decl2.c 2001/03/28 09:49:49
*************** finish_file ()
*** 3621,3630 ****
}
}
- /* Mark all functions that might deal with exception-handling as
- referenced. */
- mark_all_runtime_matches ();
-
/* We lie to the back-end, pretending that some functions are
not defined when they really are. This keeps these functions
from being put out unnecessarily. But, we must stop lying
--- 3621,3626 ----
Index: dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/dump.c,v
retrieving revision 1.53
diff -c -p -d -r1.53 dump.c
*** dump.c 2001/03/27 04:52:21 1.53
--- dump.c 2001/03/28 09:49:49
*************** cp_dump_tree (di, t)
*** 188,193 ****
--- 188,200 ----
dump_next_stmt (di, t);
break;
+ case EH_SPEC_BLOCK:
+ dump_stmt (di, t);
+ dump_child ("body", EH_SPEC_STMTS (t));
+ dump_child ("raises", EH_SPEC_RAISES (t));
+ dump_next_stmt (di, t);
+ break;
+
case PTRMEM_CST:
dump_child ("clas", PTRMEM_CST_CLASS (t));
dump_child ("mbr", PTRMEM_CST_MEMBER (t));
*************** cp_dump_tree (di, t)
*** 224,229 ****
--- 231,242 ----
case HANDLER:
dump_stmt (di, t);
dump_child ("body", HANDLER_BODY (t));
+ dump_next_stmt (di, t);
+ break;
+
+ case MUST_NOT_THROW_EXPR:
+ dump_stmt (di, t);
+ dump_child ("body", TREE_OPERAND (t, 0));
dump_next_stmt (di, t);
break;
Index: error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.153
diff -c -p -d -r1.153 error.c
*** error.c 2001/03/26 23:41:23 1.153
--- error.c 2001/03/28 09:49:49
*************** dump_expr (t, flags)
*** 2104,2110 ****
break;
case BIND_EXPR:
! output_add_character (scratch_buffer, '}');
dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
output_add_character (scratch_buffer, '}');
break;
--- 2104,2110 ----
break;
case BIND_EXPR:
! output_add_character (scratch_buffer, '{');
dump_expr (TREE_OPERAND (t, 1), flags & ~TFF_EXPR_IN_PARENS);
output_add_character (scratch_buffer, '}');
break;
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/except.c,v
retrieving revision 1.127
diff -c -p -d -r1.127 except.c
*** except.c 2001/03/28 08:25:45 1.127
--- except.c 2001/03/28 09:49:49
*************** Boston, MA 02111-1307, USA. */
*** 34,332 ****
#include "output.h"
#include "except.h"
#include "toplev.h"
- #include "eh-common.h"
static void push_eh_cleanup PARAMS ((tree));
static tree build_eh_type_type PARAMS ((tree));
! static tree call_eh_info PARAMS ((void));
! static void push_eh_info PARAMS ((void));
! static tree get_eh_info PARAMS ((void));
! static tree get_eh_value PARAMS ((void));
! #if 0
! static tree get_eh_type PARAMS ((void));
! static tree get_eh_caught PARAMS ((void));
! static tree get_eh_handlers PARAMS ((void));
! #endif
static int dtor_nothrow PARAMS ((tree));
! static tree do_pop_exception PARAMS ((tree));
! static tree build_eh_type_type_ref PARAMS ((tree));
! static tree build_terminate_handler PARAMS ((void));
! static tree alloc_eh_object 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 void initialize_handler_parm PARAMS ((tree));
- static tree expand_throw PARAMS ((tree));
- static int decl_is_java_type PARAMS ((tree decl, int err));
#include "decl.h"
#include "obstack.h"
-
- /* In a given translation unit we are constrained to catch only C++
- types or only Java types. `catch_language' holds the current type,
- and `catch_language_init' registers whether `catch_language' has
- been set. */
! static int catch_language_init = 0;
! static int catch_language;
!
! /* ======================================================================
! 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.
!
! ===================================================================== */
!
! /* ====================================================================== */
!
! /* 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 (std_identifier);
! terminate_node = build_cp_library_fn_ptr ("terminate", vtype);
TREE_THIS_VOLATILE (terminate_node) = 1;
TREE_NOTHROW (terminate_node) = 1;
if (flag_honor_std)
pop_namespace ();
-
- set_exception_lang_code (EH_LANG_C_plus_plus);
- set_exception_version_code (1);
-
- /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
- be protected with __terminate. */
- protect_cleanup_actions_with_terminate = 1;
- }
-
- /* Retrieve a pointer to the cp_eh_info node for the current exception. */
-
- static tree
- call_eh_info ()
- {
- tree fn;
-
- fn = get_identifier ("__start_cp_handler");
- if (IDENTIFIER_GLOBAL_VALUE (fn))
- fn = IDENTIFIER_GLOBAL_VALUE (fn);
- else
- {
- tree eh_info_type;
- tree cleanup_fn_type;
- tree matcher_fn_type;
- tree cp_eh_info_type;
- tree exception_desc_type;
- tree fields[8];
-
- eh_info_type = make_aggr_type (RECORD_TYPE);
- exception_desc_type = make_aggr_type (RECORD_TYPE);
-
- /* void * (*) (__eh_info *, void *, exception_descriptor *); */
- matcher_fn_type = tree_cons
- (NULL_TREE, build_pointer_type (eh_info_type), tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, build_pointer_type (exception_desc_type),
- void_list_node)));
- matcher_fn_type = build_function_type (ptr_type_node, matcher_fn_type);
- matcher_fn_type = build_pointer_type (matcher_fn_type);
-
- /* void (*) (void *); */
- cleanup_fn_type = tree_cons
- (NULL_TREE, ptr_type_node, void_list_node);
- cleanup_fn_type = build_function_type (void_type_node, cleanup_fn_type);
- cleanup_fn_type = build_pointer_type (cleanup_fn_type);
-
- /* eh-common.h
- struct __eh_info
- {
- __eh_matcher match_function;
- short language;
- short version;
- }; */
- fields[0] = build_decl (FIELD_DECL,
- get_identifier ("match_function"), ptr_type_node);
- fields[1] = build_decl (FIELD_DECL,
- get_identifier ("language"), short_integer_type_node);
- fields[2] = build_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 (eh_info_type, "__eh_info", fields, 2, ptr_type_node);
-
- /* exception_support.h
- struct cp_eh_info
- {
- __eh_info eh_info;
- void *value;
- void *type;
- cleanup_fn cleanup;
- bool caught;
- cp_eh_info *next;
- long handlers;
- void *original_value;
- }; */
- cp_eh_info_type = make_aggr_type (RECORD_TYPE);
- fields[0] = build_decl (FIELD_DECL, get_identifier ("eh_info"),
- eh_info_type);
- fields[1] = build_decl (FIELD_DECL, get_identifier ("value"),
- ptr_type_node);
- fields[2] = build_decl (FIELD_DECL, get_identifier ("type"),
- ptr_type_node);
- fields[3] = build_decl (FIELD_DECL, get_identifier ("cleanup"),
- cleanup_fn_type);
- fields[4] = build_decl (FIELD_DECL, get_identifier ("caught"),
- boolean_type_node);
- fields[5] = build_decl (FIELD_DECL, get_identifier ("next"),
- build_pointer_type (cp_eh_info_type));
- fields[6] = build_decl (FIELD_DECL, get_identifier ("handlers"),
- long_integer_type_node);
- fields[7] = build_decl (FIELD_DECL, get_identifier ("original_value"),
- 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 (cp_eh_info_type, "cp_eh_info", fields, 7, ptr_type_node);
-
- /* And now the function. */
- fn = push_library_fn (fn,
- build_function_type (build_pointer_type (cp_eh_info_type),
- void_list_node));
- }
- 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);
- }
-
- /* Returns a reference to the cp_eh_info node for the current exception. */
-
- static tree
- get_eh_info ()
- {
- /* 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);
- }
-
- /* 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. */
-
static tree
! build_eh_type_type (type)
tree type;
{
if (type == error_mark_node)
return error_mark_node;
--- 34,100 ----
#include "output.h"
#include "except.h"
#include "toplev.h"
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 choose_personality_routine PARAMS ((bool));
! static void initialize_handler_parm PARAMS ((tree, tree));
! static tree do_allocate_exception PARAMS ((tree));
! static tree do_free_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));
#include "decl.h"
#include "obstack.h"
! /* Sets up all the global eh stuff that needs to be initialized at the
start of compilation. */
void
init_exception_processing ()
{
! tree tmp;
!
if (flag_honor_std)
push_namespace (std_identifier);
!
! /* void std::terminate (); */
! 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;
if (flag_honor_std)
pop_namespace ();
! protect_cleanup_actions = build_call (terminate_node, NULL_TREE);
! /* 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);
! eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
! ? "__gxx_personality_sj0"
! : "__gxx_personality_v0");
! lang_eh_runtime_type = build_eh_type_type;
}
static tree
! prepare_eh_type (type)
tree type;
{
+ if (type == NULL_TREE)
+ return type;
if (type == error_mark_node)
return error_mark_node;
*************** build_eh_type_type (type)
*** 337,350 ****
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
! return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type));
}
/* Build the address of a typeinfo decl for use in the runtime
! matching field of the new exception model */
static tree
! build_eh_type_type_ref (type)
tree type;
{
tree exp;
--- 105,118 ----
/* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
! return type;
}
/* 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;
{
tree exp;
*************** build_eh_type_type_ref (type)
*** 352,398 ****
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);
- exp = get_tinfo_decl (type);
mark_used (exp);
exp = build1 (ADDR_EXPR, ptr_type_node, exp);
! return (exp);
}
! /* This routine is called to mark all the symbols representing runtime
! type functions in the exception table as having 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 <num; x++)
{
! exp = (tree) ptr[x];
! if (TREE_CODE (exp) == ADDR_EXPR)
! {
! exp = TREE_OPERAND (exp, 0);
! if (TREE_CODE (exp) == FUNCTION_DECL)
! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
! }
}
!
! free (ptr);
}
/* Returns nonzero if cleaning up an exception of type TYPE (which can be
--- 120,162 ----
if (type == NULL_TREE || type == error_mark_node)
return type;
! if (decl_is_java_type (type, 0))
! exp = build_java_class_ref (TREE_TYPE (type));
! else
! 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 up a call to __cxa_begin_catch, to tell the runtime that the
! exception has been handled. */
!
! static tree
! do_begin_catch ()
{
! tree fn;
!
! fn = get_identifier ("__cxa_begin_catch");
! if (IDENTIFIER_GLOBAL_VALUE (fn))
! fn = IDENTIFIER_GLOBAL_VALUE (fn);
! else
{
! /* Declare void* __cxa_begin_catch (void *). */
! tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
! fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
!
! return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
! NULL_TREE));
}
/* Returns nonzero if cleaning up an exception of type TYPE (which can be
*************** dtor_nothrow (type)
*** 415,446 ****
return TREE_NOTHROW (fn);
}
! /* Build up a call to __cp_pop_exception, to destroy the exception object
for the current catch block if no others are currently using it. */
static tree
! do_pop_exception (type)
tree type;
{
tree fn, cleanup;
! fn = get_identifier ("__cp_pop_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare void __cp_pop_exception (void *),
! as defined in exception.cc. */
! fn = push_void_library_fn
! (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node));
/* This can throw if the destructor for the exception throws. */
TREE_NOTHROW (fn) = 0;
}
! /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
! cleanup = lookup_name (get_identifier ("__exception_info"), 0);
! cleanup = build_function_call (fn, tree_cons
! (NULL_TREE, cleanup, NULL_TREE));
TREE_NOTHROW (cleanup) = dtor_nothrow (type);
return cleanup;
}
--- 179,207 ----
return TREE_NOTHROW (fn);
}
! /* Build up a call to __cxa_end_catch, to destroy the exception object
for the current catch block if no others are currently using it. */
static tree
! do_end_catch (type)
tree type;
{
tree fn, cleanup;
!
! fn = get_identifier ("__cxa_end_catch");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare void __cxa_end_catch (). */
! fn = push_void_library_fn (fn, void_list_node);
/* This can throw if the destructor for the exception throws. */
TREE_NOTHROW (fn) = 0;
}
! cleanup = build_function_call (fn, NULL_TREE);
TREE_NOTHROW (cleanup) = dtor_nothrow (type);
+
return cleanup;
}
*************** static void
*** 450,478 ****
push_eh_cleanup (type)
tree type;
{
! finish_decl_cleanup (NULL_TREE, do_pop_exception (type));
! }
!
! /* Build up a call to terminate on the function obstack, for use as an
! exception handler. */
!
! static tree
! build_terminate_handler ()
! {
! return build_function_call (terminate_node, NULL_TREE);
}
/* Return nonzero value if DECL is a Java type suitable for catch or
throw. */
! static int
decl_is_java_type (decl, err)
tree decl;
int err;
{
! int r = (TREE_CODE (decl) == POINTER_TYPE
! && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
! && TYPE_FOR_JAVA (TREE_TYPE (decl)));
if (err)
{
--- 211,230 ----
push_eh_cleanup (type)
tree type;
{
! finish_decl_cleanup (NULL_TREE, do_end_catch (type));
}
/* Return nonzero value if DECL is a Java type suitable for catch or
throw. */
! static bool
decl_is_java_type (decl, err)
tree decl;
int err;
{
! bool r = (TREE_CODE (decl) == POINTER_TYPE
! && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
! && TYPE_FOR_JAVA (TREE_TYPE (decl)));
if (err)
{
*************** decl_is_java_type (decl, err)
*** 508,578 ****
return r;
}
/* Initialize the catch parameter DECL. */
static void
! initialize_handler_parm (decl)
tree decl;
{
- tree exp;
tree init;
tree init_type;
- int lang;
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
! /* Figure out the type that the initializer is. */
init_type = TREE_TYPE (decl);
! if (TREE_CODE (init_type) != REFERENCE_TYPE
! && TREE_CODE (init_type) != POINTER_TYPE)
init_type = build_reference_type (init_type);
-
- if (decl_is_java_type (init_type, 0))
- {
- tree fn
- = builtin_function ("_Jv_exception_info",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- void_type_node,
- NULL_TREE)),
- 0, NOT_BUILT_IN, NULL_PTR);
-
- exp = build (CALL_EXPR, ptr_type_node,
- build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)),
- fn),
- NULL_TREE, NULL_TREE);
- TREE_SIDE_EFFECTS (exp) = 1;
- lang = EH_LANG_Java;
! set_exception_lang_code (EH_LANG_Java);
! set_exception_version_code (1);
! }
! else
! {
! exp = get_eh_value ();
! lang = EH_LANG_C_plus_plus;
! }
!
! if (catch_language_init)
! {
! if (lang != catch_language)
! error ("mixing C++ and Java `catch'es in single translation unit");
! }
! else
! {
! catch_language_init = 1;
! catch_language = lang;
! }
/* Since pointers are passed by value, initialize a reference to
! pointer catch parm with the address of the value slot. */
if (TREE_CODE (init_type) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
exp = build_unary_op (ADDR_EXPR, exp, 1);
! exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
init = convert_from_reference (exp);
--- 260,333 ----
return r;
}
+ static void
+ choose_personality_routine (is_java)
+ bool is_java;
+ {
+ static enum {
+ chose_none,
+ chose_cpp,
+ chose_java,
+ gave_error
+ } state;
+
+ switch (state)
+ {
+ case chose_none:
+ /* We defaulted to C++ in init_exception_processing.
+ Reconfigure for Java if we changed our minds. */
+ if (is_java)
+ eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+ ? "__gcj_personality_sj0"
+ : "__gcj_personality_v0");
+ state = (is_java ? chose_java : chose_cpp);
+ break;
+
+ case chose_cpp:
+ case chose_java:
+ if (state != (is_java ? chose_java : chose_cpp))
+ {
+ error ("mixing C++ and Java catches in a single translation unit");
+ state = gave_error;
+ }
+ break;
+
+ case gave_error:
+ break;
+ }
+ }
+
/* Initialize the catch parameter DECL. */
static void
! initialize_handler_parm (decl, exp)
tree decl;
+ tree exp;
{
tree init;
tree init_type;
/* Make sure we mark the catch param as used, otherwise we'll get a
warning about an unused ((anonymous)). */
TREE_USED (decl) = 1;
! /* Figure out the type that the initializer is. Pointers are returned
! adjusted by value from __cxa_begin_catch. Others are returned by
! reference. */
init_type = TREE_TYPE (decl);
! if (TREE_CODE (init_type) != POINTER_TYPE
! && TREE_CODE (init_type) != REFERENCE_TYPE)
init_type = build_reference_type (init_type);
! choose_personality_routine (decl_is_java_type (init_type, 0));
/* Since pointers are passed by value, initialize a reference to
! pointer catch parm with the address of the temporary. */
if (TREE_CODE (init_type) == REFERENCE_TYPE
&& TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
exp = build_unary_op (ADDR_EXPR, exp, 1);
! exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
init = convert_from_reference (exp);
*************** initialize_handler_parm (decl)
*** 584,591 ****
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
! init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
! build_terminate_handler ());
}
/* Let `cp_finish_decl' know that this initializer is ok. */
--- 339,345 ----
See also expand_default_init. */
init = ocp_convert (TREE_TYPE (decl), init,
CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
! init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
}
/* Let `cp_finish_decl' know that this initializer is ok. */
*************** expand_start_catch_block (decl)
*** 605,610 ****
--- 359,367 ----
{
tree compound_stmt_1;
tree compound_stmt_2;
+ tree exp = NULL_TREE;
+ tree type;
+ bool is_java;
if (! doing_eh (1))
return NULL_TREE;
*************** expand_start_catch_block (decl)
*** 618,651 ****
compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
note_level_for_catch ();
! if (! decl || ! decl_is_java_type (TREE_TYPE (decl), 1))
{
! /* The ordinary C++ case. */
! tree type;
! if (decl)
! type = TREE_TYPE (decl);
else
! type = NULL_TREE;
! begin_catch_block (build_eh_type_type_ref (type));
!
! push_eh_info ();
! push_eh_cleanup (type);
}
else
! {
! /* The Java case. In this case, the match_info is a pointer to
! the Java class object. We assume that the class is a
! compiled class. */
! tree ref = build_java_class_ref (TREE_TYPE (TREE_TYPE (decl)));
! begin_catch_block (build1 (ADDR_EXPR, jclass_node, ref));
! }
/* Create a binding level for the parm. */
compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
if (decl)
! initialize_handler_parm (decl);
return build_tree_list (compound_stmt_1, compound_stmt_2);
}
--- 375,428 ----
compound_stmt_1 = begin_compound_stmt (/*has_no_scope=*/0);
note_level_for_catch ();
! if (decl)
! type = prepare_eh_type (TREE_TYPE (decl));
! else
! type = NULL_TREE;
! begin_catch_block (type);
!
! is_java = false;
! if (decl)
{
! tree init;
! if (decl_is_java_type (type, 1))
! {
! /* Java only passes object via pointer and doesn't require
! adjusting. The java object is immediately before the
! generic exception header. */
! init = build_exc_ptr ();
! init = build1 (NOP_EXPR, build_pointer_type (type), init);
! init = build (MINUS_EXPR, TREE_TYPE (init), init,
! TYPE_SIZE_UNIT (TREE_TYPE (init)));
! init = build_indirect_ref (init, NULL_PTR);
! is_java = true;
! }
else
! {
! /* C++ requires that we call __cxa_begin_catch to get the
! pointer to the actual object. */
! init = do_begin_catch ();
! }
!
! exp = create_temporary_var (ptr_type_node);
! DECL_REGISTER (exp) = 1;
! cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
! finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
}
else
! finish_expr_stmt (do_begin_catch ());
+ /* C++ requires that we call __cxa_end_catch at the end of
+ processing the exception. */
+ if (! is_java)
+ push_eh_cleanup (type);
+
/* Create a binding level for the parm. */
compound_stmt_2 = begin_compound_stmt (/*has_no_scope=*/0);
if (decl)
! initialize_handler_parm (decl, exp);
return build_tree_list (compound_stmt_1, compound_stmt_2);
}
*************** expand_end_catch_block (blocks)
*** 678,1043 ****
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
}
- /* An exception spec is implemented more or less like:
-
- try {
- function body;
- } catch (...) {
- void *p[] = { typeid(raises) };
- __check_eh_spec (p, count);
- }
-
- __check_eh_spec in exception.cc handles all the details. */
-
tree
! expand_start_eh_spec ()
{
! return begin_try_block ();
}
void
! expand_end_eh_spec (raises, try_block)
! tree raises;
! tree try_block;
{
! tree tmp, fn, decl, types = NULL_TREE;
! tree blocks;
! tree handler;
! int count = 0;
!
! finish_try_block (try_block);
! handler = begin_handler ();
! blocks = finish_handler_parms (NULL_TREE, handler);
!
! if (TREE_VALUE (raises) == NULL_TREE)
! {
! fn = get_identifier ("__check_null_eh_spec");
! if (IDENTIFIER_GLOBAL_VALUE (fn))
! fn = IDENTIFIER_GLOBAL_VALUE (fn);
! else
! {
! tmp = build_function_type (void_type_node, void_list_node);
! fn = push_throw_library_fn (fn, tmp);
! /* Since the spec doesn't allow any exceptions, this call will
! never throw. We use push_throw_library_fn because we do want
! TREE_THIS_VOLATILE to be set. */
! TREE_NOTHROW (fn) = 1;
! }
! tmp = NULL_TREE;
! }
! else
! {
! /* Build up an array of type_infos. */
! for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
! {
! types = tree_cons
! (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
! ++count;
! }
!
! types = build_nt (CONSTRUCTOR, NULL_TREE, types);
! TREE_HAS_CONSTRUCTOR (types) = 1;
!
! /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
! tmp = build_cplus_array_type (const_ptr_type_node, NULL_TREE);
! decl = build_decl (VAR_DECL, NULL_TREE, tmp);
! DECL_ARTIFICIAL (decl) = 1;
! DECL_INITIAL (decl) = types;
! DECL_CONTEXT (decl) = current_function_decl;
! cp_finish_decl (decl, types, NULL_TREE, 0);
!
! decl = decay_conversion (decl);
!
! fn = get_identifier ("__check_eh_spec");
! if (IDENTIFIER_GLOBAL_VALUE (fn))
! fn = IDENTIFIER_GLOBAL_VALUE (fn);
! else
! {
! tmp = tree_cons
! (NULL_TREE, integer_type_node, tree_cons
! (NULL_TREE, TREE_TYPE (decl), void_list_node));
! tmp = build_function_type (void_type_node, tmp);
!
! fn = push_throw_library_fn (fn, tmp);
! }
! tmp = tree_cons (NULL_TREE, build_int_2 (count, 0),
! tree_cons (NULL_TREE, decl, NULL_TREE));
! }
! tmp = build_call (fn, tmp);
! finish_expr_stmt (tmp);
! finish_handler (blocks, handler);
! finish_handler_sequence (try_block);
}
! /* This is called to expand all the toplevel exception handling
! finalization for a function. It should only be called once per
! function. */
! void
! expand_exception_blocks ()
{
! do_pending_stack_adjust ();
! if (catch_clauses)
{
! rtx funcend = gen_label_rtx ();
! emit_jump (funcend);
!
! /* We cannot protect n regions this way if we must flow into the
! EH region through the top of the region, as we have to with
! the setjmp/longjmp approach. */
! if (USING_SJLJ_EXCEPTIONS == 0)
! expand_eh_region_start ();
!
! emit_insns (catch_clauses);
! catch_clauses = catch_clauses_last = NULL_RTX;
!
! if (USING_SJLJ_EXCEPTIONS == 0)
! expand_eh_region_end (build_terminate_handler ());
!
! emit_insns (catch_clauses);
! catch_clauses = catch_clauses_last = NULL_RTX;
! emit_label (funcend);
}
}
! /* Return a pointer to a buffer for an exception object of type TYPE. */
static tree
! alloc_eh_object (type)
! tree type;
{
! tree fn, exp;
! fn = get_identifier ("__eh_alloc");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare __eh_alloc (size_t), as defined in exception.cc. */
! tree tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
! fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
! exp = build_function_call (fn, tree_cons
! (NULL_TREE, size_in_bytes (type), NULL_TREE));
! exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
! return exp;
}
! /* Expand a throw statement. This follows the following
! algorithm:
!
! 1. Allocate space to save the current PC onto the stack.
! 2. Generate and emit a label and save its address into the
! newly allocated stack space since we can't save the pc directly.
! 3. If this is the first call to throw in this function:
! generate a label for the throw block
! 4. jump to the throw block label. */
! static tree
! expand_throw (exp)
tree exp;
{
tree fn;
if (! doing_eh (1))
return error_mark_node;
! if (exp
! && decl_is_java_type (TREE_TYPE (exp), 1))
{
! /* A Java `throw' statement. */
! tree args = tree_cons (NULL_TREE, exp, NULL);
!
! fn = get_identifier (USING_SJLJ_EXCEPTIONS
! ? "_Jv_Sjlj_Throw"
! : "_Jv_Throw");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare _Jv_Throw (void *), as defined in Java's
! exception.cc. */
tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
tmp = build_function_type (ptr_type_node, tmp);
fn = push_throw_library_fn (fn, tmp);
}
! exp = build_function_call (fn, args);
}
else if (exp)
{
tree throw_type;
! tree cleanup = NULL_TREE, e;
tree stmt_expr;
tree compound_stmt;
tree try_block;
begin_init_stmts (&stmt_expr, &compound_stmt);
/* throw expression */
/* First, decay it. */
exp = decay_conversion (exp);
! /* The CLEANUP_TYPE is the internal type of a destructor. Under
! the old ABI, destructors are two-argument functions; under
! the new ABI they take only one argument. */
! if (cleanup_type == NULL_TREE)
! {
! tree arg_types;
!
! arg_types = void_list_node;
! arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
! cleanup_type = (build_pointer_type
! (build_function_type (void_type_node, arg_types)));
! }
!
! if (TYPE_PTR_P (TREE_TYPE (exp)))
! throw_type = build_eh_type_type (TREE_TYPE (exp));
! else
! {
! tree object, ptr;
!
! /* OK, this is kind of wacky. The standard says that we call
! terminate when the exception handling mechanism, after
! completing evaluation of the expression to be thrown but
! before the exception is caught (_except.throw_), calls a
! user function that exits via an uncaught exception.
! So we have to protect the actual initialization of the
! exception object with terminate(), but evaluate the
! expression first. Since there could be temps in the
! expression, we need to handle that, too. We also expand
! the call to __eh_alloc first (which doesn't matter, since
! it can't throw). */
! my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
! /* Store the throw expression into a temp. This can be less
! efficient than storing it into the allocated space directly, but
! if we allocated the space first we would have to deal with
! cleaning it up if evaluating this expression throws. */
! if (TREE_SIDE_EFFECTS (exp))
! {
! tree temp = create_temporary_var (TREE_TYPE (exp));
! DECL_INITIAL (temp) = exp;
! cp_finish_decl (temp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
! exp = temp;
! }
! /* Allocate the space for the exception. */
! ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
! finish_expr_stmt (ptr);
! try_block = begin_try_block ();
! object = build_indirect_ref (ptr, NULL_PTR);
! exp = build_modify_expr (object, INIT_EXPR, exp);
! if (exp == error_mark_node)
! error (" in thrown expression");
! finish_expr_stmt (exp);
! finish_cleanup_try_block (try_block);
! finish_cleanup (build_terminate_handler (), try_block);
! throw_type = build_eh_type_type (TREE_TYPE (object));
! if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
! {
! cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! complete_dtor_identifier,
! 0);
! cleanup = TREE_VALUE (cleanup);
! mark_used (cleanup);
! mark_addressable (cleanup);
! /* Pretend it's a normal function. */
! cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
! }
! exp = ptr;
}
!
! /* Cast EXP to `void *' so that it will match the prototype for
! __cp_push_exception. */
! exp = convert (ptr_type_node, exp);
!
! if (cleanup == NULL_TREE)
{
cleanup = build_int_2 (0, 0);
TREE_TYPE (cleanup) = cleanup_type;
}
! fn = cp_push_exception_identifier;
! if (IDENTIFIER_GLOBAL_VALUE (fn))
! fn = IDENTIFIER_GLOBAL_VALUE (fn);
! else
! {
! /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
! as defined in exception.cc. */
! tree tmp;
! tmp = tree_cons
! (NULL_TREE, ptr_type_node, tree_cons
! (NULL_TREE, ptr_type_node, tree_cons
! (NULL_TREE, cleanup_type, void_list_node)));
! fn = push_void_library_fn (fn, tmp);
! }
! e = tree_cons (NULL_TREE, exp, tree_cons
! (NULL_TREE, throw_type, tree_cons
! (NULL_TREE, cleanup, NULL_TREE)));
! finish_expr_stmt (build_function_call (fn, e));
exp = finish_init_stmts (stmt_expr, compound_stmt);
}
else
{
! /* rethrow current exception; note that it's no longer caught. */
! tree fn = get_identifier ("__uncatch_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
! /* Declare void __uncatch_exception (void)
! as defined in exception.cc. */
! fn = push_void_library_fn (fn, void_list_node);
exp = build_function_call (fn, NULL_TREE);
}
-
- return exp;
- }
-
- /* Build a throw expression. */
-
- tree
- build_throw (e)
- tree e;
- {
- if (e == error_mark_node)
- return e;
-
- if (processing_template_decl)
- return build_min (THROW_EXPR, void_type_node, e);
-
- if (e == null_node)
- cp_warning ("throwing NULL, which has integral, not pointer type");
-
- if (e != NULL_TREE)
- {
- if (!is_admissible_throw_operand (e))
- return error_mark_node;
- }
! e = expand_throw (e);
! e = build1 (THROW_EXPR, void_type_node, e);
! TREE_SIDE_EFFECTS (e) = 1;
! TREE_USED (e) = 1;
! return e;
}
/* Make sure TYPE is complete, pointer to complete, reference to
--- 455,709 ----
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
}
tree
! begin_eh_spec_block ()
{
! tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
! add_stmt (r);
! return r;
}
void
! finish_eh_spec_block (raw_raises, eh_spec_block)
! tree raw_raises;
! tree eh_spec_block;
{
! tree raises;
! RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block));
! /* Strip cv quals, etc, from the specification types. */
! for (raises = NULL_TREE;
! raw_raises && TREE_VALUE (raw_raises);
! raw_raises = TREE_CHAIN (raw_raises))
! raises = tree_cons (NULL_TREE, prepare_eh_type (TREE_VALUE (raw_raises)),
! raises);
! EH_SPEC_RAISES (eh_spec_block) = raises;
}
! /* Return a pointer to a buffer for an exception object of type TYPE. */
! static tree
! do_allocate_exception (type)
! tree type;
{
! tree fn;
! fn = get_identifier ("__cxa_allocate_exception");
! if (IDENTIFIER_GLOBAL_VALUE (fn))
! fn = IDENTIFIER_GLOBAL_VALUE (fn);
! else
{
! /* Declare void *__cxa_allocate_exception(size_t). */
! tree tmp = tree_cons (NULL_TREE, c_size_type_node, void_list_node);
! fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
+
+ return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type),
+ NULL_TREE));
}
! /* Call __cxa_free_exception from a cleanup. This is invoked when
! a constructor for a thrown object throws. */
static tree
! do_free_exception (ptr)
! tree ptr;
{
! tree fn;
! fn = get_identifier ("__cxa_free_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare void __cxa_free_exception (void *). */
! fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node,
! void_list_node));
}
! return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE));
}
! /* Build a throw expression. */
! tree
! build_throw (exp)
tree exp;
{
tree fn;
+ if (exp == error_mark_node)
+ return exp;
+
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, exp);
+
+ if (exp == null_node)
+ cp_warning ("throwing NULL, which has integral, not pointer type");
+
+ if (exp != NULL_TREE)
+ {
+ if (!is_admissible_throw_operand (exp))
+ return error_mark_node;
+ }
+
if (! doing_eh (1))
return error_mark_node;
! if (exp && decl_is_java_type (TREE_TYPE (exp), 1))
{
! tree fn = get_identifier ("_Jv_Throw");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
! /* Declare void _Jv_Throw (void *). */
tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
tmp = build_function_type (ptr_type_node, tmp);
fn = push_throw_library_fn (fn, tmp);
}
! exp = build_function_call (fn, tree_cons (NULL_TREE, exp, NULL_TREE));
}
else if (exp)
{
tree throw_type;
! tree cleanup;
tree stmt_expr;
tree compound_stmt;
tree try_block;
+ tree object, ptr;
+ tree tmp;
+ fn = get_identifier ("__cxa_throw");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* The CLEANUP_TYPE is the internal type of a destructor. */
+ if (cleanup_type == NULL_TREE)
+ {
+ tmp = void_list_node;
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = build_function_type (void_type_node, tmp);
+ cleanup_type = build_pointer_type (tmp);
+ }
+
+ /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */
+ /* ??? Second argument is supposed to be "std::type_info*". */
+ tmp = void_list_node;
+ tmp = tree_cons (NULL_TREE, cleanup_type, tmp);
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = tree_cons (NULL_TREE, ptr_type_node, tmp);
+ tmp = build_function_type (void_type_node, tmp);
+ fn = push_throw_library_fn (fn, tmp);
+ }
+
begin_init_stmts (&stmt_expr, &compound_stmt);
/* throw expression */
/* First, decay it. */
exp = decay_conversion (exp);
! /* OK, this is kind of wacky. The standard says that we call
! terminate when the exception handling mechanism, after
! completing evaluation of the expression to be thrown but
! before the exception is caught (_except.throw_), calls a
! user function that exits via an uncaught exception.
! So we have to protect the actual initialization of the
! exception object with terminate(), but evaluate the
! expression first. Since there could be temps in the
! expression, we need to handle that, too. We also expand
! the call to __cxa_allocate_exception first (which doesn't
! matter, since it can't throw). */
! my_friendly_assert (stmts_are_full_exprs_p () == 1, 19990926);
! /* Store the throw expression into a temp. This can be less
! efficient than storing it into the allocated space directly, but
! if we allocated the space first we would have to deal with
! cleaning it up if evaluating this expression throws. */
! if (TREE_SIDE_EFFECTS (exp))
! {
! tmp = create_temporary_var (TREE_TYPE (exp));
! DECL_INITIAL (tmp) = exp;
! cp_finish_decl (tmp, exp, NULL_TREE, LOOKUP_ONLYCONVERTING);
! exp = tmp;
! }
! /* Allocate the space for the exception. */
! ptr = create_temporary_var (ptr_type_node);
! DECL_REGISTER (ptr) = 1;
! cp_finish_decl (ptr, NULL_TREE, NULL_TREE, LOOKUP_ONLYCONVERTING);
! tmp = do_allocate_exception (TREE_TYPE (exp));
! tmp = build_modify_expr (ptr, INIT_EXPR, tmp);
! finish_expr_stmt (tmp);
! object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
! object = build_indirect_ref (object, NULL_PTR);
! try_block = begin_try_block ();
! exp = build_modify_expr (object, INIT_EXPR, exp);
! if (exp == error_mark_node)
! error (" in thrown expression");
! finish_expr_stmt (exp);
! finish_cleanup_try_block (try_block);
! finish_cleanup (do_free_exception (ptr), try_block);
! throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
! if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
! {
! cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! complete_dtor_identifier, 0);
! cleanup = TREE_VALUE (cleanup);
! mark_used (cleanup);
! mark_addressable (cleanup);
! /* Pretend it's a normal function. */
! cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
}
! else
{
cleanup = build_int_2 (0, 0);
TREE_TYPE (cleanup) = cleanup_type;
}
! tmp = tree_cons (NULL_TREE, cleanup, NULL_TREE);
! tmp = tree_cons (NULL_TREE, throw_type, tmp);
! tmp = tree_cons (NULL_TREE, ptr, tmp);
! tmp = build_function_call (fn, tmp);
! /* ??? Indicate that this function call throws throw_type. */
+ finish_expr_stmt (tmp);
+
exp = finish_init_stmts (stmt_expr, compound_stmt);
}
else
{
! /* Rethrow current exception. */
! tree fn = get_identifier ("__cxa_rethrow");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
! {
! /* Declare void __cxa_rethrow (void). */
! fn = push_throw_library_fn
! (fn, build_function_type (void_type_node, void_list_node));
! }
exp = build_function_call (fn, NULL_TREE);
}
! exp = build1 (THROW_EXPR, void_type_node, exp);
! return exp;
}
/* Make sure TYPE is complete, pointer to complete, reference to
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/expr.c,v
retrieving revision 1.56
diff -c -p -d -r1.56 expr.c
*** expr.c 2001/02/12 09:58:18 1.56
--- expr.c 2001/03/28 09:49:49
*************** cplus_expand_expr (exp, target, tmode, m
*** 88,93 ****
--- 88,94 ----
tree type = TREE_TYPE (exp);
register enum machine_mode mode = TYPE_MODE (type);
register enum tree_code code = TREE_CODE (exp);
+ rtx ret;
/* No sense saving up arithmetic to be done
if it's all in the wrong mode to form part of an address.
*************** cplus_expand_expr (exp, target, tmode, m
*** 103,117 ****
target, tmode, modifier);
case OFFSET_REF:
! {
! return expand_expr (default_conversion (resolve_offset_ref (exp)),
! target, tmode, EXPAND_NORMAL);
! }
case THROW_EXPR:
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
- expand_internal_throw ();
return NULL;
case EMPTY_CLASS_EXPR:
/* We don't need to generate any code for an empty class. */
--- 104,121 ----
target, tmode, modifier);
case OFFSET_REF:
! return expand_expr (default_conversion (resolve_offset_ref (exp)),
! target, tmode, EXPAND_NORMAL);
case THROW_EXPR:
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
return NULL;
+
+ case MUST_NOT_THROW_EXPR:
+ expand_eh_region_start ();
+ ret = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+ expand_eh_region_end_must_not_throw (build_call (terminate_node, 0));
+ return ret;
case EMPTY_CLASS_EXPR:
/* We don't need to generate any code for an empty class. */
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.197
diff -c -p -d -r1.197 semantics.c
*** semantics.c 2001/03/28 08:25:45 1.197
--- semantics.c 2001/03/28 09:49:49
*************** static tree simplify_aggr_init_exprs_r P
*** 51,56 ****
--- 51,57 ----
static void deferred_type_access_control PARAMS ((void));
static void emit_associated_thunks PARAMS ((tree));
static void genrtl_try_block PARAMS ((tree));
+ static void genrtl_eh_spec_block PARAMS ((tree));
static void genrtl_handler PARAMS ((tree));
static void genrtl_catch_block PARAMS ((tree));
static void genrtl_ctor_stmt PARAMS ((tree));
*************** genrtl_try_block (t)
*** 575,588 ****
{
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
! expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
}
else
{
if (!FN_TRY_BLOCK_P (t))
emit_line_note (input_filename, lineno);
- expand_start_try_stmts ();
expand_stmt (TRY_STMTS (t));
if (FN_TRY_BLOCK_P (t))
--- 576,589 ----
{
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
! expand_eh_region_end_cleanup (TRY_HANDLERS (t));
}
else
{
if (!FN_TRY_BLOCK_P (t))
emit_line_note (input_filename, lineno);
+ expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
if (FN_TRY_BLOCK_P (t))
*************** genrtl_try_block (t)
*** 603,608 ****
--- 604,624 ----
}
}
+ /* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
+
+ static void
+ genrtl_eh_spec_block (t)
+ tree t;
+ {
+ expand_eh_region_start ();
+ expand_stmt (EH_SPEC_STMTS (t));
+ expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
+ build_call (call_unexpected_node,
+ tree_cons (NULL_TREE,
+ build_exc_ptr (),
+ NULL_TREE)));
+ }
+
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
appropriate. */
*************** genrtl_handler (t)
*** 706,718 ****
genrtl_do_pushlevel ();
expand_stmt (HANDLER_BODY (t));
if (!processing_template_decl)
! {
! /* Fall to outside the try statement when done executing
! handler and we fall off end of handler. This is jump
! Lresume in the documentation. */
! expand_goto (top_label_entry (&caught_return_label_stack));
! end_catch_handler ();
! }
}
/* Begin a handler. Returns a HANDLER if appropriate. */
--- 722,728 ----
genrtl_do_pushlevel ();
expand_stmt (HANDLER_BODY (t));
if (!processing_template_decl)
! expand_end_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
*************** finish_handler_parms (decl, handler)
*** 757,769 ****
return blocks;
}
! /* Generate the RTL for a CATCH_BLOCK. */
static void
genrtl_catch_block (type)
tree type;
{
! start_catch_handler (type);
}
/* Note the beginning of a handler for TYPE. This function is called
--- 767,779 ----
return blocks;
}
! /* Generate the RTL for a START_CATCH_STMT. */
static void
genrtl_catch_block (type)
tree type;
{
! expand_start_catch (type);
}
/* Note the beginning of a handler for TYPE. This function is called
*************** cp_expand_stmt (t)
*** 2209,2214 ****
--- 2219,2228 ----
genrtl_try_block (t);
break;
+ case EH_SPEC_BLOCK:
+ genrtl_eh_spec_block (t);
+ break;
+
case HANDLER:
genrtl_handler (t);
break;
*************** genrtl_finish_function (fn)
*** 2614,2622 ****
&& current_function_return_value == NULL_TREE
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- if (flag_exceptions)
- expand_exception_blocks ();
/* If this function is supposed to return a value, ensure that
we do not fall into the cleanups by mistake. The end of our
--- 2628,2633 ----
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.237
diff -c -p -d -r1.237 tree.c
*** tree.c 2001/03/23 01:49:11 1.237
--- tree.c 2001/03/28 09:49:50
*************** cp_statement_code_p (code)
*** 1037,1042 ****
--- 1037,1043 ----
case RETURN_INIT:
case TRY_BLOCK:
case HANDLER:
+ case EH_SPEC_BLOCK:
return 1;
default: