📄 cp-except.c
字号:
if (in_try_block (1)) {#if 1 my_friendly_abort (35);#else expand_raise (decl);#endif } else if (! current_function_decl) error ("invalid throw outside of functions"); else {#if 0 /* Test this raise against what this function permits. */ tree names = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)); while (names) { if (decl == TREE_TYPE (names)) break; names = TREE_CHAIN (names); } if (names == NULL_TREE) { error ("current function not declared to raise exception `%s'", IDENTIFIER_POINTER (name)); return; }#endif } store_expr (exp, EHS_parms_as_rtx, 0); /* Set the global exception handler stack's NAME field to the `name' of this exception. The global exception handler stack is the container for the exception object we just built. We go through a function call to make life easier when debugging. */#if 0 expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);#else parms = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, EHS_name, 0), build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 0))); expand_expr (build_function_call (BIR, parms), 0, 0, 0);#endif /* Activate thrower. If we are inside a TRY statement, we can cheat and not do this, saving a longjmp. */ if (in_try_block (1) == 0) { sets_exception_throw_decl = 1; emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); } if (xexp == NULL_TREE) { /* Invoke destructors for current procedure or handler. */ if (! expand_escape_except ()) compiler_error ("except nesting botch"); /* Throw via `longjmp'... Done as side-effect of goto. */ } /* To avoid spurious warning messages, we add a goto to the end of the function. This code is dead, and the compiler should know how to delete it, but for now, we are stuck with it. */ if (! for_reraise && TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) expand_null_return ();}treecplus_expand_start_catch (raise_id) tree raise_id;{ tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id); tree decl; tree cond; if (cname == error_mark_node) { decl = error_mark_node; cond = error_mark_node; } else { decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1); if (decl == NULL_TREE) cond = error_mark_node; else cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), build (COMPONENT_REF, ptr_type_node, current_exception_decl, TREE_OPERAND (EHS_name, 1))); } expand_start_cond (cond, 0); /* Does nothing right now. */ expand_catch (decl); if (current_exception_type && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) { /* Make a cleanup for the name-specific exception object now in scope. */ tree cleanup = maybe_build_cleanup (current_exception_object); expand_start_bindings (0); expand_decl_cleanup (NULL_TREE, cleanup); } return decl;}treeansi_expand_start_catch (raise_type) tree raise_type;{ tree decl = ansi_exception_object_lookup (raise_type); tree cond; if (decl == NULL_TREE) cond = error_mark_node; else cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), build (COMPONENT_REF, ptr_type_node, current_exception_decl, TREE_OPERAND (EHS_name, 1))); expand_start_cond (cond, 0); /* Does nothing right now. */ expand_catch (decl); return decl;}voidcplus_expand_end_catch (for_reraise) int for_reraise;{ if (current_exception_type && TYPE_NEEDS_DESTRUCTOR (current_exception_type)) { /* Destroy the specific exception object now in scope. */ expand_end_bindings (getdecls (), 0, 1); } if (for_reraise) { if (! expand_escape_except ()) my_friendly_abort (36); } else { if (! expand_end_catch ()) my_friendly_abort (37); } expand_end_cond ();}/* Reraise an exception. If EXCEPTIONS is NULL_TREE, it means reraise whatever exception was caught. If EXCEPTIONS is an IDENTIFIER_NODE, it means reraise the exception object named by EXCEPTIONS. This must be a variable declared in an `except' clause. If EXCEPTIONS is a TREE_LIST, it is the list of exceptions we are willing to reraise. */voidcplus_expand_reraise (exceptions) tree exceptions;{ tree ex_ptr; tree ex_object = current_exception_object; rtx ex_ptr_as_rtx; if (exceptions && TREE_CODE (exceptions) == IDENTIFIER_NODE) { /* Don't get tripped up if its TREE_TYPE is `error_mark_node'. */ ex_object = IDENTIFIER_LOCAL_VALUE (exceptions); if (ex_object == NULL_TREE || TREE_CODE (ex_object) != INDIRECT_REF) { error ("`%s' is not an exception decl", IDENTIFIER_POINTER (exceptions)); return; } my_friendly_assert (TREE_CODE (TREE_OPERAND (ex_object, 0)) == VAR_DECL, 204); exceptions = NULL_TREE; } ex_ptr = build1 (NOP_EXPR, ptr_type_node, TREE_OPERAND (ex_object, 0)); ex_ptr_as_rtx = expand_expr (ex_ptr, 0, 0, 0); /* reraise ALL, used by compiler. */ if (exceptions == NULL_TREE) { /* Now treat reraise like catch/raise. */ expand_catch (error_mark_node); expand_raise (error_mark_node); emit_move_insn (EHS_name_as_rtx, current_exception_name_as_rtx); store_expr (EHS_parms_as_rtx, current_exception_parms_as_rtx, 0); if (in_try_block (1) == 0) { sets_exception_throw_decl = 1; emit_move_insn (DECL_RTL (exception_throw_decl), const1_rtx); } /* Set to zero so that destructor will not be called. */ emit_move_insn (ex_ptr_as_rtx, const0_rtx); if (! expand_escape_except ()) my_friendly_abort (38); /* To avoid spurious warning messages, we add a goto to the end of the function. This code is dead, and the compiler should know how to delete it, but for now, we are stuck with it. */ if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) expand_null_return (); return; } /* reraise from a list of exceptions. */ while (exceptions) { tree type = lookup_exception_type (current_class_type, current_class_name, exceptions); if (type == NULL_TREE) { error ("`%s' is not an exception type", IDENTIFIER_POINTER (TREE_VALUE (exceptions))); current_exception_type = NULL_TREE; TREE_TYPE (ex_object) = error_mark_node; TREE_TYPE (ex_ptr) = error_mark_node; } else { current_exception_type = type; /* In-place union. */ TREE_TYPE (ex_object) = type; TREE_TYPE (ex_ptr) = TYPE_POINTER_TO (type); } /* Now treat reraise like catch/raise. */ cplus_expand_start_catch (exceptions); cplus_expand_raise (exceptions, NULL_TREE, ex_ptr, 1); /* Set to zero so that destructor will not be called. */ if (TREE_TYPE (ex_ptr) != error_mark_node) emit_move_insn (ex_ptr_as_rtx, const0_rtx); cplus_expand_end_catch (1); exceptions = TREE_CHAIN (exceptions); } /* Don't propagate any unhandled exceptions. */ expand_expr (call_to_unhandled_exception (), 0, VOIDmode, 0); /* To avoid spurious warning messages, we add a goto to the end of the function. This code is dead, and the compiler should know how to delete it, but for now, we are stuck with it. */ if (TREE_TYPE (DECL_RESULT (current_function_decl)) != void_type_node) expand_null_return ();}voidsetup_exception_throw_decl (){ tree call_to_longjmp, parms; int old = suspend_momentary (); exception_throw_decl = build_decl (VAR_DECL, get_identifier (THROW_NAME), integer_type_node); pushdecl (exception_throw_decl); parms = tree_cons (NULL_TREE, EHS_handler, build_tree_list (0, integer_one_node)); call_to_longjmp = build_function_call (BILJ, parms); expand_decl (exception_throw_decl); expand_decl_cleanup (exception_throw_decl, build (COND_EXPR, void_type_node, exception_throw_decl, call_to_longjmp, integer_zero_node)); DECL_INITIAL (exception_throw_decl) = integer_zero_node; sets_exception_throw_decl = 0; resume_momentary (old); /* Cache these, since they won't change throughout the function. */ EHS_parms_as_rtx = expand_expr (EHS_parms, 0, 0, 0); EHS_name_as_rtx = expand_expr (EHS_name, 0, 0, 0);}voidinit_exception_processing (){ extern tree unhandled_exception_fndecl; tree cname = get_identifier ("ExceptionHandler"); tree field, chain; tree ctor, dtor; tree jmp_buf_type = build_array_type (integer_type_node, build_index_type (build_int_2 (_JBLEN-1, 0))); tree jmp_buf_arg_type = build_pointer_type (integer_type_node); tree parmtypes = hash_tree_chain (jmp_buf_arg_type, void_list_node); tree setjmp_fndecl, longjmp_fndecl, raise_fndecl; int old_interface_only = interface_only; int old_interface_unknown = interface_unknown; interface_only = 1; interface_unknown = 0; EHS_type = xref_tag (record_type_node, cname, NULL_TREE); push_lang_context (lang_name_c); setjmp_fndecl = define_function ("setjmp", build_function_type (integer_type_node, parmtypes), NOT_BUILT_IN, pushdecl, 0); BISJ = default_conversion (setjmp_fndecl); parmtypes = hash_tree_chain (jmp_buf_arg_type, hash_tree_chain (integer_type_node, void_list_node)); longjmp_fndecl = define_function ("longjmp", build_function_type (void_type_node, parmtypes), NOT_BUILT_IN, pushdecl, 0); raise_fndecl = define_function ("__raise_exception", build_function_type (void_type_node, hash_tree_chain (ptr_type_node, hash_tree_chain (build_pointer_type (ptr_type_node), void_list_node))), NOT_BUILT_IN, pushdecl, 0); BILJ = default_conversion (longjmp_fndecl); BIR = default_conversion (raise_fndecl); BIUE = default_conversion (unhandled_exception_fndecl); pop_lang_context (); /* finish_struct will pop this. */ pushclass (EHS_type, 0); field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node); chain = field; field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"), build_pointer_type (default_function_type)); TREE_CHAIN (field) = chain; chain = field; field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type); TREE_CHAIN (field) = chain; chain = field; field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"), TYPE_POINTER_TO (EHS_type)); TREE_CHAIN (field) = chain; chain = field; ctor = build_lang_decl (FUNCTION_DECL, cname, build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); DECL_CONSTRUCTOR_P (ctor) = 1; TREE_STATIC (ctor) = 1; TREE_PUBLIC (ctor) = 1; DECL_EXTERNAL (ctor) = 1; grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0); grok_ctor_properties (EHS_type, ctor); finish_decl (pushdecl (ctor), 0, 0, 0); /* Must copy the node here because the FUNCTION_DECL used inside the struct ain't the same as the FUNCTION_DECL we stick into the global binding contour. */ ctor = copy_node (ctor); TREE_CHAIN (ctor) = chain; chain = ctor; dtor = build_lang_decl (FUNCTION_DECL, cname, build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node)); TREE_STATIC (dtor) = 1; TREE_PUBLIC (dtor) = 1; DECL_EXTERNAL (dtor) = 1; grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0); finish_decl (pushdecl (dtor), 0, 0, 0); /* Copy for the same reason as copying ctor. */ dtor = copy_node (dtor); TREE_CHAIN (dtor) = chain; chain = dtor; TYPE_HAS_CONSTRUCTOR (EHS_type) = 1; TYPE_HAS_DESTRUCTOR (EHS_type) = 1; finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0, 0); interface_only = old_interface_only; interface_unknown = old_interface_unknown;}voidinit_exception_processing_1 (){ register tree EHS_id = get_identifier ("exceptionHandlerStack"); EHS_decl = IDENTIFIER_GLOBAL_VALUE (EHS_id); /* If we have no other definition, default to library implementation. */ if (EHS_decl == NULL_TREE) { EHS_decl = build_decl (VAR_DECL, EHS_id, TYPE_POINTER_TO (EHS_type)); /* If we don't push this, its definition, should it be encountered, will not be seen. */ EHS_decl = pushdecl (EHS_decl); DECL_EXTERNAL (EHS_decl) = 1; TREE_STATIC (EHS_decl) = 1; TREE_PUBLIC (EHS_decl) = 1; finish_decl (EHS_decl, 0, 0, 0); } else if (TREE_CODE (EHS_decl) != VAR_DECL || TREE_TYPE (EHS_decl) != TYPE_POINTER_TO (EHS_type)) fatal ("exception handling declarations conflict with compiler's internal model"); if (EHS_prev == NULL_TREE) { register tree EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl); EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0); EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0); EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0); EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -