diff options
author | Jason Merrill <jason@yorick.cygnus.com> | 1997-10-31 09:52:55 +0000 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 1997-10-31 04:52:55 -0500 |
commit | 6874c2647b322a34cd25c74c2cf2d0b374683df7 (patch) | |
tree | 4369bf2e164b02228c2c4a5d1ae1ceb8ded7b16a /gcc/cp/except.c | |
parent | 59fe8c2c207c0e4309ee5c9734ed16bd096eeedd (diff) | |
download | gcc-6874c2647b322a34cd25c74c2cf2d0b374683df7.zip gcc-6874c2647b322a34cd25c74c2cf2d0b374683df7.tar.gz gcc-6874c2647b322a34cd25c74c2cf2d0b374683df7.tar.bz2 |
[multiple changes]
Fri Oct 31 01:45:31 1997 Jason Merrill <jason@yorick.cygnus.com>
* libgcc2.c (L_eh): Define __eh_pc.
Replace __eh_type with generic pointer __eh_info.
Fri Oct 31 01:47:57 1997 Jason Merrill <jason@yorick.cygnus.com>
Support for nested exceptions.
* tinfo2.cc (__is_pointer): New fn.
* exception.cc (struct cp_eh_info): Define.
(__cp_exception_info, __uncatch_exception): New fns.
(__cp_push_exception, __cp_pop_exception): New fns.
* except.c: Lose saved_throw_{type,value,cleanup,in_catch}.
Lose empty_fndecl.
(init_exception_processing): Likewise. __eh_pc is now external.
(push_eh_info): New fn.
(get_eh_{info,value,type,caught}): New fns.
(push_eh_cleanup): Just call __cp_pop_exception.
(expand_start_catch_block): Use push_eh_info. Start the eh region
sooner.
(expand_end_eh_spec): Use push_eh_info.
(expand_throw): Call __cp_push_exception to set up the exception info.
Just pass the destructor or 0 as the cleanup. Call __uncatch_exception
when we rethrow.
(expand_builtin_throw): Don't refer to empty_fndecl.
From-SVN: r16248
Diffstat (limited to 'gcc/cp/except.c')
-rw-r--r-- | gcc/cp/except.c | 354 |
1 files changed, 244 insertions, 110 deletions
diff --git a/gcc/cp/except.c b/gcc/cp/except.c index fe0a1b5..4d3622b 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -180,8 +180,6 @@ static tree Unwind; /* Holds a ready to emit call to "terminate". */ static tree TerminateFunctionCall; -static tree empty_fndecl; - /* ====================================================================== */ @@ -196,14 +194,6 @@ static tree empty_fndecl; /* Holds the pc for doing "throw" */ static tree saved_pc; -/* Holds the type of the thing being thrown. */ -static tree saved_throw_type; -/* Holds the value being thrown. */ -static tree saved_throw_value; -/* Holds the cleanup for the value being thrown. */ -static tree saved_cleanup; -/* Indicates if we are in a catch clause. */ -static tree saved_in_catch; extern int throw_used; extern rtx catch_clauses; @@ -290,12 +280,6 @@ init_exception_processing () tree_cons (NULL_TREE, ptr_type_node, void_list_node)), NOT_BUILT_IN, NULL_PTR); - empty_fndecl - = builtin_function ("__empty", - vtype, - NOT_BUILT_IN, NULL_PTR); - DECL_EXTERNAL (empty_fndecl) = 1; - TREE_PUBLIC (empty_fndecl) = 1; Unexpected = default_conversion (unexpected_fndecl); Terminate = default_conversion (terminate_fndecl); @@ -310,47 +294,118 @@ init_exception_processing () pop_lang_context (); - declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); - d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc")); - d = start_decl (d, declspecs, 0); - DECL_COMMON (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0); - saved_pc = lookup_name (get_identifier ("__eh_pc"), 0); - - declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); - d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type")); - d = start_decl (d, declspecs, 0); - DECL_COMMON (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0); - saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0); - - declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); - d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value")); - d = start_decl (d, declspecs, 0); - DECL_COMMON (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0); - saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0); - - declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE); - d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup")); - d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE); - d = start_decl (d, declspecs, 0); - DECL_COMMON (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0); - saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0); - - declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE); - d = get_identifier ("__eh_in_catch"); - d = start_decl (d, declspecs, 0); - DECL_COMMON (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0); - saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0); + d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node); + TREE_PUBLIC (d) = 1; + DECL_EXTERNAL (d) = 1; + DECL_ARTIFICIAL (d) = 1; + cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); + saved_pc = d; /* 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 + and save it in the current binding level. */ + +static void +push_eh_info () +{ + tree decl, fn; + + fn = get_identifier ("__cp_exception_info"); + if (IDENTIFIER_GLOBAL_VALUE (fn)) + fn = IDENTIFIER_GLOBAL_VALUE (fn); + else + { + tree t, fields[5]; + + /* Declare cp_eh_info * __cp_exception_info (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. */ + t = make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"), + ptr_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"), + ptr_type_node); + fields[2] = 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[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"), + boolean_type_node); + fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"), + build_pointer_type (t)); + finish_builtin_type (t, "cp_eh_info", fields, 5, 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); + assemble_external (fn); + pop_obstacks (); + } + fn = build_function_call (fn, NULL_TREE); + + /* 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. */ + +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. */ + +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); +} + /* Build a type value for use at runtime for a type that is matched against by the exception handling system. */ @@ -396,19 +451,37 @@ build_eh_type (exp) return build_eh_type_type (TREE_TYPE (exp)); } -/* This routine creates the cleanup for the exception handling object. */ +/* This routine creates the cleanup for the current exception. */ static void push_eh_cleanup () { /* All cleanups must last longer than normal. */ int yes = suspend_momentary (); + 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. */ + push_obstacks_nochange (); + end_temporary_allocation (); + fn = build_lang_decl (FUNCTION_DECL, fn, + build_function_type (void_type_node, + void_list_node)); + DECL_EXTERNAL (fn) = 1; + TREE_PUBLIC (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + pushdecl_top_level (fn); + make_function_rtl (fn); + assemble_external (fn); + pop_obstacks (); + } /* Arrange to do a dynamically scoped cleanup upon exit from this region. */ - tree cleanup = build_function_call (saved_cleanup, NULL_TREE); - cleanup = build (COMPOUND_EXPR, void_type_node, cleanup, - build_modify_expr (saved_in_catch, NOP_EXPR, - build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node))); + cleanup = build_function_call (fn, NULL_TREE); expand_decl_cleanup (NULL_TREE, cleanup); resume_momentary (yes); @@ -456,6 +529,23 @@ expand_start_catch_block (declspecs, declarator) emit_line_note (input_filename, lineno); + push_eh_info (); + + /* If we are not doing setjmp/longjmp EH, because we are reordered + out of line, we arrange to rethrow in the outer context so as to + skip through the terminate region we are nested in, should we + encounter an exception in the catch handler. + + If we are doing setjmp/longjmp EH, we need to skip through the EH + object cleanup region. This isn't quite right, as we really need + to clean the object up, but we cannot do that until we track + multiple EH objects. + + Matches the end in expand_end_catch_block. */ + expand_eh_region_start (); + + push_eh_cleanup (); + if (declspecs) { tree exp; @@ -467,12 +557,6 @@ expand_start_catch_block (declspecs, declarator) if (decl == NULL_TREE) { error ("invalid catch parameter"); - - /* This is cheap, but we want to maintain the data - structures. */ - - expand_eh_region_start (); - return; } @@ -486,11 +570,11 @@ expand_start_catch_block (declspecs, declarator) && TREE_CODE (init_type) != POINTER_TYPE) init_type = build_reference_type (init_type); - exp = saved_throw_value; + exp = get_eh_value (); exp = expr_tree_cons (NULL_TREE, build_eh_type_type (TREE_TYPE (decl)), expr_tree_cons (NULL_TREE, - saved_throw_type, + get_eh_type (), expr_tree_cons (NULL_TREE, exp, NULL_TREE))); exp = build_function_call (CatchMatch, exp); call_rtx = expand_call (exp, NULL_RTX, 0); @@ -505,8 +589,6 @@ expand_start_catch_block (declspecs, declarator) /* if it returned FALSE, jump over the catch block, else fall into it */ emit_jump_insn (gen_beq (false_label_rtx)); - push_eh_cleanup (); - init = convert_from_reference (save_expr (make_tree (init_type, call_rtx))); /* Do we need the below two lines? */ @@ -515,27 +597,9 @@ expand_start_catch_block (declspecs, declarator) decl = pushdecl (decl); cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); } - else - { - push_eh_cleanup (); - /* Fall into the catch all section. */ - } - - emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx); - - /* If we are not doing setjmp/longjmp EH, because we are reordered - out of line, we arrange to rethrow in the outer context so as to - skip through the terminate region we are nested in, should we - encounter an exception in the catch handler. - - If we are doing setjmp/longjmp EH, we need to skip through the EH - object cleanup region. This isn't quite right, as we really need - to clean the object up, but we cannot do that until we track - multiple EH objects. - - Matches the end in expand_end_catch_block. */ - expand_eh_region_start (); + init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node); + expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL); emit_line_note (input_filename, lineno); } @@ -845,7 +909,8 @@ expand_builtin_throw () #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE if (DONT_ACCESS_GBLS_AFTER_EPILOGUE) { - t = make_tree (build_pointer_type (TREE_TYPE (empty_fndecl)), + t = build_function_type (void_type_node, void_list_node); + t = make_tree (build_pointer_type (t), hard_function_value (ptr_type_node, NULL_TREE)); t = build_function_call (t, NULL_TREE); @@ -965,6 +1030,9 @@ expand_end_eh_spec (raises) emit_label (check); emit_move_insn (flag, const1_rtx); cont = gen_label_rtx (); + + push_eh_info (); + while (raises) { tree exp; @@ -973,11 +1041,11 @@ expand_end_eh_spec (raises) if (match_type) { /* check TREE_VALUE (raises) here */ - exp = saved_throw_value; + exp = get_eh_value (); exp = expr_tree_cons (NULL_TREE, build_eh_type_type (match_type), expr_tree_cons (NULL_TREE, - saved_throw_type, + get_eh_type (), expr_tree_cons (NULL_TREE, exp, NULL_TREE))); exp = build_function_call (CatchMatch, exp); assemble_external (TREE_OPERAND (CatchMatch, 0)); @@ -1123,6 +1191,8 @@ expand_throw (exp) tree exp; { rtx label; + tree fn; + static tree cleanup_type; if (! doing_eh (1)) return; @@ -1130,12 +1200,26 @@ expand_throw (exp) if (exp) { tree throw_type; - tree cleanup = empty_fndecl, e; + tree cleanup = NULL_TREE, e; /* throw expression */ /* First, decay it. */ exp = decay_conversion (exp); + /* cleanup_type is void (*)(void *, int), + the internal type of a destructor. */ + if (cleanup_type == NULL_TREE) + { + push_obstacks_nochange (); + end_temporary_allocation (); + cleanup_type = build_pointer_type + (build_function_type + (void_type_node, tree_cons + (NULL_TREE, ptr_type_node, tree_cons + (NULL_TREE, integer_type_node, void_list_node)))); + pop_obstacks (); + } + if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE) { throw_type = build_eh_type (exp); @@ -1156,33 +1240,83 @@ expand_throw (exp) object = build_indirect_ref (exp, NULL_PTR); throw_type = build_eh_type (object); - /* Build __tcf_ function. */ - cleanup = start_anon_func (); - object = build_delete (TREE_TYPE (exp), saved_throw_value, - integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0); - expand_expr (object, const0_rtx, VOIDmode, 0); - end_anon_func (); - mark_addressable (cleanup); + if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) + { + cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), + dtor_identifier, 0); + cleanup = TREE_VALUE (cleanup); + mark_addressable (cleanup); + /* Pretend it's a normal function. */ + cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); + } } - if (cleanup == empty_fndecl) - assemble_external (empty_fndecl); - - e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type); - expand_expr (e, const0_rtx, VOIDmode, 0); + if (cleanup == NULL_TREE) + { + cleanup = build_int_2 (0, 0); + TREE_TYPE (cleanup) = cleanup_type; + } - e = build_modify_expr (saved_throw_value, NOP_EXPR, exp); - e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e); - expand_expr (e, const0_rtx, VOIDmode, 0); + fn = get_identifier ("__cp_push_exception"); + 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; + push_obstacks_nochange (); + end_temporary_allocation (); + 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 = build_lang_decl (FUNCTION_DECL, fn, + build_function_type (void_type_node, tmp)); + DECL_EXTERNAL (fn) = 1; + TREE_PUBLIC (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + pushdecl_top_level (fn); + make_function_rtl (fn); + assemble_external (fn); + pop_obstacks (); + } - cleanup = build_unary_op (ADDR_EXPR, cleanup, 0); - cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup); - expand_expr (cleanup, const0_rtx, VOIDmode, 0); + /* The throw expression is a full-expression. */ + exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); + e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons + (NULL_TREE, throw_type, expr_tree_cons + (NULL_TREE, cleanup, NULL_TREE))); + e = build_function_call (fn, e); + expand_expr (e, const0_rtx, VOIDmode, 0); } else { - /* rethrow current exception */ - /* This part is easy, as we don't have to do anything 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. */ + push_obstacks_nochange (); + end_temporary_allocation (); + fn = build_lang_decl (FUNCTION_DECL, fn, + build_function_type (void_type_node, + void_list_node)); + DECL_EXTERNAL (fn) = 1; + TREE_PUBLIC (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + pushdecl_top_level (fn); + make_function_rtl (fn); + assemble_external (fn); + pop_obstacks (); + } + + exp = build_function_call (fn, NULL_TREE); + expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL); } if (exceptions_via_longjmp) |