mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-27 23:04:46 +08:00
[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
This commit is contained in:
parent
59fe8c2c20
commit
6874c2647b
@ -1,3 +1,8 @@
|
||||
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 00:34:55 1996 J"orn Rennecke <amylaar@cygnus.co.uk>
|
||||
|
||||
* expr.c (expand_increment): When enqueing a postincrement for a MEM,
|
||||
|
@ -1,3 +1,24 @@
|
||||
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.
|
||||
|
||||
Thu Oct 23 02:01:30 1997 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* pt.c (instantiate_decl): SET_DECL_IMPLICIT_INSTANTIATION on new decl.
|
||||
|
354
gcc/cp/except.c
354
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)
|
||||
|
@ -73,6 +73,79 @@ unexpected ()
|
||||
__unexpected_func ();
|
||||
}
|
||||
|
||||
/* C++-specific state about the current exception.
|
||||
This must match init_exception_processing(). */
|
||||
|
||||
struct cp_eh_info
|
||||
{
|
||||
void *value;
|
||||
void *type;
|
||||
void (*cleanup)(void *, int);
|
||||
bool caught;
|
||||
cp_eh_info *next;
|
||||
};
|
||||
|
||||
/* Language-specific EH info pointer, defined in libgcc2. */
|
||||
|
||||
extern cp_eh_info *__eh_info; // actually void*
|
||||
|
||||
/* Is P the type_info node for a pointer of some kind? */
|
||||
|
||||
extern bool __is_pointer (void *);
|
||||
|
||||
/* Compiler hook to return a pointer to the info for the current exception.
|
||||
Used by get_eh_info (). */
|
||||
|
||||
extern "C" cp_eh_info *
|
||||
__cp_exception_info (void)
|
||||
{
|
||||
return __eh_info;
|
||||
}
|
||||
|
||||
/* Compiler hook to push a new exception onto the stack.
|
||||
Used by expand_throw(). */
|
||||
|
||||
extern "C" void
|
||||
__cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
|
||||
{
|
||||
cp_eh_info *p = new cp_eh_info;
|
||||
p->value = value;
|
||||
p->type = type;
|
||||
p->cleanup = cleanup;
|
||||
p->caught = false;
|
||||
p->next = __eh_info;
|
||||
__eh_info = p;
|
||||
}
|
||||
|
||||
/* Compiler hook to pop an exception that has been finalized. Used by
|
||||
push_eh_cleanup(). */
|
||||
|
||||
extern "C" void
|
||||
__cp_pop_exception (void)
|
||||
{
|
||||
cp_eh_info *p = __eh_info;
|
||||
|
||||
if (p->cleanup)
|
||||
/* 3 is a magic value for destructors; see build_delete(). */
|
||||
p->cleanup (p->value, 3);
|
||||
else if (__is_pointer (p->type))
|
||||
/* do nothing; pointers are passed directly in p->value. */;
|
||||
else
|
||||
delete p->value;
|
||||
|
||||
__eh_info = p->next;
|
||||
delete p;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__uncatch_exception (void)
|
||||
{
|
||||
cp_eh_info *p = __cp_exception_info ();
|
||||
if (p)
|
||||
p->caught = false;
|
||||
/* otherwise __throw will call terminate(); don't crash here. */
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__throw_bad_cast (void)
|
||||
{
|
||||
@ -91,12 +164,13 @@ __throw_bad_exception (void)
|
||||
throw bad_exception ();
|
||||
}
|
||||
|
||||
/* Has the current exception been caught? */
|
||||
|
||||
bool
|
||||
uncaught_exception ()
|
||||
{
|
||||
extern void *__eh_type;
|
||||
extern bool __eh_in_catch;
|
||||
return __eh_type && ! __eh_in_catch;
|
||||
cp_eh_info *p = __cp_exception_info ();
|
||||
return p && ! p->caught;
|
||||
}
|
||||
|
||||
const char * exception::
|
||||
|
@ -258,6 +258,18 @@ __throw_type_match_rtti (void *catch_type_r, void *throw_type_r, void *objptr)
|
||||
return new_objptr;
|
||||
}
|
||||
|
||||
/* Called from __cp_pop_exception. Is P the type_info node for a pointer
|
||||
of some kind? */
|
||||
|
||||
bool
|
||||
__is_pointer (void *p)
|
||||
{
|
||||
const type_info *t = reinterpret_cast <const type_info *>(p);
|
||||
const __pointer_type_info *pt =
|
||||
dynamic_cast <const __pointer_type_info *> (t);
|
||||
return pt != 0;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__rtti_ptr (void *addr, const char *n, const type_info *ti)
|
||||
{ new (addr) __pointer_type_info (n, *ti); }
|
||||
|
@ -3109,7 +3109,9 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
|
||||
|
||||
/* Shared exception handling support routines. */
|
||||
|
||||
extern void *__eh_type;
|
||||
/* Language-specific information about the active exception(s). If there
|
||||
are no active exceptions, it is set to 0. */
|
||||
void *__eh_info;
|
||||
|
||||
void
|
||||
__default_terminate ()
|
||||
@ -3224,7 +3226,7 @@ __sjthrow ()
|
||||
/* We must call terminate if we try and rethrow an exception, when
|
||||
there is no exception currently active and when there are no
|
||||
handlers left. */
|
||||
if (! __eh_type || (*dhc) == top_elt)
|
||||
if (! __eh_info || (*dhc) == top_elt)
|
||||
__terminate ();
|
||||
|
||||
/* Find the jmpbuf associated with the top element of the dynamic
|
||||
@ -3307,7 +3309,7 @@ __sjpopnthrow ()
|
||||
/* This value identifies the place from which an exception is being
|
||||
thrown. */
|
||||
|
||||
extern void *__eh_pc;
|
||||
void *__eh_pc;
|
||||
|
||||
#ifdef EH_TABLE_LOOKUP
|
||||
|
||||
@ -3652,7 +3654,7 @@ __throw ()
|
||||
/* This is required for C++ semantics. We must call terminate if we
|
||||
try and rethrow an exception, when there is no exception currently
|
||||
active. */
|
||||
if (! __eh_type)
|
||||
if (! __eh_info)
|
||||
__terminate ();
|
||||
|
||||
/* Start at our stack frame. */
|
||||
|
Loading…
Reference in New Issue
Block a user