aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/except.c
diff options
context:
space:
mode:
authorJason Merrill <jason@yorick.cygnus.com>1997-10-31 09:52:55 +0000
committerJason Merrill <jason@gcc.gnu.org>1997-10-31 04:52:55 -0500
commit6874c2647b322a34cd25c74c2cf2d0b374683df7 (patch)
tree4369bf2e164b02228c2c4a5d1ae1ceb8ded7b16a /gcc/cp/except.c
parent59fe8c2c207c0e4309ee5c9734ed16bd096eeedd (diff)
downloadgcc-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.c354
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)