From 6c20b7e97e520789f6fcd11f3b6326394fbc1697 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 21 Nov 1997 20:29:06 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 10 +++ gcc/cp/decl.c | 2 +- gcc/cp/except.c | 148 +++++++++++++++++++------------------------ gcc/cp/exception.cc | 51 ++++++++++++++- gcc/cp/inc/exception | 4 +- gcc/cp/tinfo2.cc | 3 +- 6 files changed, 131 insertions(+), 87 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c88e084709c..88c9d2edac0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ Fri Nov 21 12:22:07 1997 Jason Merrill + * 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. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 39e7a5afa4f..7b2e1c24622 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 *'. */ diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 5c2344d43d7..bd26053dfce 100644 --- a/gcc/cp/except.c +++ b/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 diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index 2d1ae081247..28071183c0f 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -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) { diff --git a/gcc/cp/inc/exception b/gcc/cp/inc/exception index d38806b81c4..3e66beed518 100644 --- a/gcc/cp/inc/exception +++ b/gcc/cp/inc/exception @@ -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++" diff --git a/gcc/cp/tinfo2.cc b/gcc/cp/tinfo2.cc index 128661c1cd2..53134889527 100644 --- a/gcc/cp/tinfo2.cc +++ b/gcc/cp/tinfo2.cc @@ -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;