extern int throw_used;
extern rtx catch_clauses;
+extern tree const_ptr_type_node;
/* ========================================================================= */
? "__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);
#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 ();
-
- 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;
+ 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);
+ expand_start_all_catch ();
+ expand_start_catch_block (NULL_TREE, NULL_TREE);
- 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 ();
+ /* Build up an array of type_infos. */
+ for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
+ {
+ types = expr_tree_cons
+ (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
+ ++count;
+ }
- expand_eh_region_end (second_try);
-
- emit_label (check);
- emit_move_insn (flag, const1_rtx);
- cont = gen_label_rtx ();
+ types = build_nt (CONSTRUCTOR, NULL_TREE, types);
+ TREE_HAS_CONSTRUCTOR (types) = 1;
- push_eh_info ();
+ /* 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);
- while (raises)
+ fn = get_identifier ("__check_eh_spec");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- 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);
- }
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
- raises = TREE_CHAIN (raises);
- }
- emit_move_insn (flag, const0_rtx);
- emit_label (cont);
- emit_indirect_jump (ret);
- emit_label (end);
-
- do_pending_stack_adjust ();
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
+ 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);
- 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
terminate ();
}
-static unexpected_handler __unexpected_func = __default_unexpected;
+static unexpected_handler __unexpected_func __attribute__((__noreturn__))
+ = __default_unexpected;
terminate_handler
set_terminate (terminate_handler func)
/* 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)
{