📄 except.c
字号:
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); 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); pop_obstacks (); } mark_used (fn); 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 finalization for a function. It should only be called once per function. */voidexpand_exception_blocks (){ do_pending_stack_adjust (); push_to_sequence (catch_clauses); expand_leftover_cleanups (); do_pending_stack_adjust (); catch_clauses = get_insns (); end_sequence (); /* Do this after we expand leftover cleanups, so that the expand_eh_region_end that expand_end_eh_spec does will match the right expand_eh_region_start, and make sure it comes out before the terminate protected region. */ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) { expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))); do_pending_stack_adjust (); push_to_sequence (catch_clauses); expand_leftover_cleanups (); do_pending_stack_adjust (); catch_clauses = get_insns (); end_sequence (); } if (catch_clauses) { rtx funcend = gen_label_rtx (); emit_jump (funcend); /* We cannot protect n regions this way if we must flow into the EH region through the top of the region, as we have to with the setjmp/longjmp approach. */ if (exceptions_via_longjmp == 0) expand_eh_region_start (); emit_insns (catch_clauses); catch_clauses = NULL_RTX; if (exceptions_via_longjmp == 0) expand_eh_region_end (build_terminate_handler ()); expand_leftover_cleanups (); emit_label (funcend); }}treestart_anon_func (){ static int counter = 0; int old_interface_unknown = interface_unknown; char name[32]; tree params; tree t; push_cp_function_context (NULL_TREE); push_to_top_level (); /* No need to mangle this. */ push_lang_context (lang_name_c); interface_unknown = 1; params = void_list_node; /* tcf stands for throw clean function. */ sprintf (name, "__tcf_%d", counter++); t = make_call_declarator (get_identifier (name), params, NULL_TREE, NULL_TREE); start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"), void_list_node), t, NULL_TREE, 0); store_parm_decls (); pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); emit_line_note (input_filename, lineno); interface_unknown = old_interface_unknown; pop_lang_context (); return current_function_decl;}voidend_anon_func (){ expand_end_bindings (getdecls (), 1, 0); poplevel (1, 0, 0); pop_momentary (); finish_function (lineno, 0, 0); pop_from_top_level (); pop_cp_function_context (NULL_TREE);}/* Return a pointer to a buffer for an exception object of type TYPE. */static treealloc_eh_object (type) tree type;{ tree fn, exp; fn = get_identifier ("__eh_alloc"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { /* Declare __eh_alloc (size_t), as defined in exception.cc. */ tree tmp; push_obstacks_nochange (); end_temporary_allocation (); tmp = tree_cons (NULL_TREE, sizetype, void_list_node); fn = build_lang_decl (FUNCTION_DECL, fn, build_function_type (ptr_type_node, tmp)); DECL_EXTERNAL (fn) = 1; TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; pushdecl_top_level (fn); make_function_rtl (fn); pop_obstacks (); } mark_used (fn); exp = build_function_call (fn, expr_tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE)); exp = build1 (NOP_EXPR, build_pointer_type (type), exp); return exp;}/* Expand a throw statement. This follows the following algorithm: 1. Allocate space to save the current PC onto the stack. 2. Generate and emit a label and save its address into the newly allocated stack space since we can't save the pc directly. 3. If this is the first call to throw in this function: generate a label for the throw block 4. jump to the throw block label. */voidexpand_throw (exp) tree exp;{ tree fn; static tree cleanup_type; if (! doing_eh (1)) return; if (exp) { tree throw_type; 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 (TYPE_PTR_P (TREE_TYPE (exp))) throw_type = build_eh_type (exp); else { tree object, ptr; /* OK, this is kind of wacky. The WP says that we call terminate when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (_except.throw_), calls a user function that exits via an uncaught exception. So we have to protect the actual initialization of the exception object with terminate(), but evaluate the expression first. We also expand the call to __eh_alloc first. Since there could be temps in the expression, we need to handle that, too. */ expand_start_target_temps ();#if 0 /* Unfortunately, this doesn't work. */ preexpand_calls (exp);#else /* Store the throw expression into a temp. This can be less efficient than storing it into the allocated space directly, but oh well. To do this efficiently we would need to insinuate ourselves into expand_call. */ if (TREE_SIDE_EFFECTS (exp)) { tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); DECL_ARTIFICIAL (temp) = 1; DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1); DECL_INITIAL (temp) = exp; cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); exp = temp; }#endif /* Allocate the space for the exception. */ ptr = save_expr (alloc_eh_object (TREE_TYPE (exp))); expand_expr (ptr, const0_rtx, VOIDmode, 0); expand_eh_region_start (); object = build_indirect_ref (ptr, NULL_PTR); exp = build_modify_expr (object, INIT_EXPR, exp); if (exp == error_mark_node) error (" in thrown expression"); expand_expr (exp, const0_rtx, VOIDmode, 0); expand_eh_region_end (build_terminate_handler ()); expand_end_target_temps (); throw_type = build_eh_type (object); if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object))) { cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), dtor_identifier, 0); cleanup = TREE_VALUE (cleanup); mark_used (cleanup); mark_addressable (cleanup); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup); } exp = ptr; } /* Cast EXP to `void *' so that it will match the prototype for __cp_push_exception. */ exp = convert (ptr_type_node, exp); if (cleanup == NULL_TREE) { cleanup = build_int_2 (0, 0); TREE_TYPE (cleanup) = cleanup_type; } 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); pop_obstacks (); } mark_used (fn); 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; 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); pop_obstacks (); } mark_used (fn); exp = build_function_call (fn, NULL_TREE); expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL); } expand_internal_throw ();}/* Build a throw expression. */treebuild_throw (e) tree e;{ if (e == error_mark_node) return e; if (processing_template_decl) return build_min (THROW_EXPR, void_type_node, e); if (e == null_node) cp_warning ("throwing NULL, which has integral, not pointer type"); e = build1 (THROW_EXPR, void_type_node, e); TREE_SIDE_EFFECTS (e) = 1; TREE_USED (e) = 1; return e;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -