except.c (expand_start_eh_spec): Use the try/catch code.
* except.c (expand_start_eh_spec): Use the try/catch code. (expand_end_eh_spec): Likewise. Call __check_eh_spec instead of doing everything inline. (init_exception_processing): throw_type_match now takes const void pointers. * exception.cc (__check_eh_spec): New fn. * inc/exception: Neither terminate nor unexpected return. * decl.c: Make const_ptr_type_node public. * tinfo2.cc (__throw_type_match_rtti): Take the typeinfos constly. From-SVN: r16651
This commit is contained in:
parent
d32ecec207
commit
6c20b7e97e
6 changed files with 131 additions and 87 deletions
|
@ -1,5 +1,15 @@
|
|||
Fri Nov 21 12:22:07 1997 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* except.c (expand_start_eh_spec): Use the try/catch code.
|
||||
(expand_end_eh_spec): Likewise. Call __check_eh_spec instead of
|
||||
doing everything inline.
|
||||
(init_exception_processing): throw_type_match now takes
|
||||
const void pointers.
|
||||
* exception.cc (__check_eh_spec): New fn.
|
||||
* inc/exception: Neither terminate nor unexpected return.
|
||||
* decl.c: Make const_ptr_type_node public.
|
||||
* tinfo2.cc (__throw_type_match_rtti): Take the typeinfos constly.
|
||||
|
||||
* except.c (expand_start_catch_block): We only need the rethrow
|
||||
region for non-sjlj exceptions.
|
||||
(expand_end_catch_block): Likewise. Use outer_context_label_stack.
|
||||
|
|
|
@ -239,7 +239,7 @@ tree void_zero_node;
|
|||
/* Nodes for types `void *' and `const void *'. */
|
||||
|
||||
tree ptr_type_node;
|
||||
static tree const_ptr_type_node;
|
||||
tree const_ptr_type_node;
|
||||
|
||||
/* Nodes for types `char *' and `const char *'. */
|
||||
|
||||
|
|
148
gcc/cp/except.c
148
gcc/cp/except.c
|
@ -197,6 +197,7 @@ static tree saved_pc;
|
|||
|
||||
extern int throw_used;
|
||||
extern rtx catch_clauses;
|
||||
extern tree const_ptr_type_node;
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
|
@ -263,8 +264,8 @@ init_exception_processing ()
|
|||
? "__throw_type_match_rtti"
|
||||
: "__throw_type_match",
|
||||
build_function_type (ptr_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
tree_cons (NULL_TREE, const_ptr_type_node,
|
||||
tree_cons (NULL_TREE, const_ptr_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
void_list_node)))),
|
||||
NOT_BUILT_IN, NULL_PTR);
|
||||
|
@ -1020,101 +1021,84 @@ expand_builtin_throw ()
|
|||
#endif /* DWARF2_UNWIND_INFO */
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
void
|
||||
expand_start_eh_spec ()
|
||||
{
|
||||
expand_eh_region_start ();
|
||||
expand_start_try_stmts ();
|
||||
}
|
||||
|
||||
static void
|
||||
expand_end_eh_spec (raises)
|
||||
tree raises;
|
||||
{
|
||||
tree expr, second_try;
|
||||
rtx check = gen_label_rtx ();
|
||||
rtx cont;
|
||||
rtx ret = gen_reg_rtx (Pmode);
|
||||
rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
|
||||
rtx end = gen_label_rtx ();
|
||||
tree tmp, fn, decl, types = NULL_TREE;
|
||||
int count = 0;
|
||||
|
||||
expr = make_node (RTL_EXPR);
|
||||
TREE_TYPE (expr) = void_type_node;
|
||||
RTL_EXPR_RTL (expr) = const0_rtx;
|
||||
TREE_SIDE_EFFECTS (expr) = 1;
|
||||
do_pending_stack_adjust ();
|
||||
start_sequence_for_rtl_expr (expr);
|
||||
cont = gen_label_rtx ();
|
||||
emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
|
||||
emit_jump (check);
|
||||
emit_label (cont);
|
||||
jumpif (make_tree (integer_type_node, flag), end);
|
||||
do_function_call (Terminate, NULL_TREE, NULL_TREE);
|
||||
assemble_external (TREE_OPERAND (Terminate, 0));
|
||||
emit_barrier ();
|
||||
do_pending_stack_adjust ();
|
||||
RTL_EXPR_SEQUENCE (expr) = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
second_try = expr;
|
||||
expand_start_all_catch ();
|
||||
expand_start_catch_block (NULL_TREE, NULL_TREE);
|
||||
|
||||
expr = make_node (RTL_EXPR);
|
||||
TREE_TYPE (expr) = void_type_node;
|
||||
RTL_EXPR_RTL (expr) = const0_rtx;
|
||||
TREE_SIDE_EFFECTS (expr) = 1;
|
||||
do_pending_stack_adjust ();
|
||||
start_sequence_for_rtl_expr (expr);
|
||||
|
||||
cont = gen_label_rtx ();
|
||||
emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
|
||||
emit_jump (check);
|
||||
emit_label (cont);
|
||||
jumpif (make_tree (integer_type_node, flag), end);
|
||||
expand_eh_region_start ();
|
||||
do_function_call (Unexpected, NULL_TREE, NULL_TREE);
|
||||
assemble_external (TREE_OPERAND (Unexpected, 0));
|
||||
emit_barrier ();
|
||||
|
||||
expand_eh_region_end (second_try);
|
||||
|
||||
emit_label (check);
|
||||
emit_move_insn (flag, const1_rtx);
|
||||
cont = gen_label_rtx ();
|
||||
|
||||
push_eh_info ();
|
||||
|
||||
while (raises)
|
||||
/* Build up an array of type_infos. */
|
||||
for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
|
||||
{
|
||||
tree exp;
|
||||
tree match_type = TREE_VALUE (raises);
|
||||
|
||||
if (match_type)
|
||||
{
|
||||
/* check TREE_VALUE (raises) here */
|
||||
exp = get_eh_value ();
|
||||
exp = expr_tree_cons (NULL_TREE,
|
||||
build_eh_type_type (match_type),
|
||||
expr_tree_cons (NULL_TREE,
|
||||
get_eh_type (),
|
||||
expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
|
||||
exp = build_function_call (CatchMatch, exp);
|
||||
assemble_external (TREE_OPERAND (CatchMatch, 0));
|
||||
|
||||
jumpif (exp, cont);
|
||||
}
|
||||
|
||||
raises = TREE_CHAIN (raises);
|
||||
types = expr_tree_cons
|
||||
(NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
|
||||
++count;
|
||||
}
|
||||
emit_move_insn (flag, const0_rtx);
|
||||
emit_label (cont);
|
||||
emit_indirect_jump (ret);
|
||||
emit_label (end);
|
||||
|
||||
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_array_type (const_ptr_type_node, NULL_TREE);
|
||||
decl = build_decl (VAR_DECL, NULL_TREE, tmp);
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
DECL_INITIAL (decl) = types;
|
||||
cp_finish_decl (decl, types, NULL_TREE, 0, 0);
|
||||
|
||||
decl = decay_conversion (decl);
|
||||
|
||||
fn = get_identifier ("__check_eh_spec");
|
||||
if (IDENTIFIER_GLOBAL_VALUE (fn))
|
||||
fn = IDENTIFIER_GLOBAL_VALUE (fn);
|
||||
else
|
||||
{
|
||||
push_obstacks_nochange ();
|
||||
end_temporary_allocation ();
|
||||
|
||||
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);
|
||||
|
||||
do_pending_stack_adjust ();
|
||||
RTL_EXPR_SEQUENCE (expr) = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
expand_eh_region_end (expr);
|
||||
fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
|
||||
DECL_EXTERNAL (fn) = 1;
|
||||
TREE_PUBLIC (fn) = 1;
|
||||
DECL_ARTIFICIAL (fn) = 1;
|
||||
TREE_THIS_VOLATILE (fn) = 1;
|
||||
pushdecl_top_level (fn);
|
||||
make_function_rtl (fn);
|
||||
assemble_external (fn);
|
||||
pop_obstacks ();
|
||||
}
|
||||
|
||||
tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
|
||||
(NULL_TREE, decl, NULL_TREE));
|
||||
tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
|
||||
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
|
||||
expand_end_catch_block ();
|
||||
expand_end_all_catch ();
|
||||
}
|
||||
|
||||
/* This is called to expand all the toplevel exception handling
|
||||
|
|
|
@ -47,7 +47,8 @@ __default_unexpected ()
|
|||
terminate ();
|
||||
}
|
||||
|
||||
static unexpected_handler __unexpected_func = __default_unexpected;
|
||||
static unexpected_handler __unexpected_func __attribute__((__noreturn__))
|
||||
= __default_unexpected;
|
||||
|
||||
terminate_handler
|
||||
set_terminate (terminate_handler func)
|
||||
|
@ -159,6 +160,54 @@ __uncatch_exception (void)
|
|||
/* otherwise __throw will call terminate(); don't crash here. */
|
||||
}
|
||||
|
||||
/* As per [except.unexpected]:
|
||||
If an exception is thrown, we check it against the spec. If it doesn't
|
||||
match, we call unexpected (). If unexpected () throws, we check that
|
||||
exception against the spec. If it doesn't match, if the spec allows
|
||||
bad_exception we throw that; otherwise we call terminate ().
|
||||
|
||||
The compiler treats an exception spec as a try block with a generic
|
||||
handler that just calls this function with a list of the allowed
|
||||
exception types, so we have an active exception that can be rethrown.
|
||||
|
||||
This function does not return. */
|
||||
|
||||
extern "C" void
|
||||
__check_eh_spec (int n, const void **spec)
|
||||
{
|
||||
cp_eh_info *p = __cp_exception_info ();
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti (spec[i], p->type, p->value))
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
unexpected ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// __exception_info is an artificial var pushed into each catch block.
|
||||
p = __exception_info;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti (spec[i], p->type, p->value))
|
||||
throw;
|
||||
}
|
||||
|
||||
const type_info &bad_exc = typeid (bad_exception);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (__throw_type_match_rtti (spec[i], &bad_exc, p->value))
|
||||
throw bad_exception ();
|
||||
}
|
||||
|
||||
terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
__throw_bad_cast (void)
|
||||
{
|
||||
|
|
|
@ -29,9 +29,9 @@ typedef void (*terminate_handler) ();
|
|||
typedef void (*unexpected_handler) ();
|
||||
|
||||
terminate_handler set_terminate (terminate_handler);
|
||||
void terminate (void);
|
||||
void terminate (void) __attribute__ ((__noreturn__));
|
||||
unexpected_handler set_unexpected (unexpected_handler);
|
||||
void unexpected (void);
|
||||
void unexpected (void) __attribute__ ((__noreturn__));
|
||||
bool uncaught_exception ();
|
||||
} // extern "C++"
|
||||
|
||||
|
|
|
@ -119,7 +119,8 @@ struct __array_type_info : public type_info {
|
|||
variables and thrown objects. */
|
||||
|
||||
extern "C" void*
|
||||
__throw_type_match_rtti (void *catch_type_r, void *throw_type_r, void *objptr)
|
||||
__throw_type_match_rtti (const void *catch_type_r, const void *throw_type_r,
|
||||
void *objptr)
|
||||
{
|
||||
const type_info &catch_type = *(const type_info *)catch_type_r;
|
||||
const type_info &throw_type = *(const type_info *)throw_type_r;
|
||||
|
|
Loading…
Add table
Reference in a new issue