📄 except.c
字号:
{ return build_component_ref (get_eh_info (), get_identifier ("handlers"), NULL_TREE, 0);}#endif/* Build a type value for use at runtime for a type that is matched against by the exception handling system. */static treebuild_eh_type_type (type) tree type;{ const char *typestring; tree exp; if (type == error_mark_node) return error_mark_node; /* peel back references, so they match. */ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* Peel off cv qualifiers. */ type = TYPE_MAIN_VARIANT (type); if (flag_rtti) return build1 (ADDR_EXPR, ptr_type_node, get_typeid_1 (type)); typestring = build_overload_name (type, 1, 1); exp = combine_strings (build_string (strlen (typestring)+1, typestring)); return build1 (ADDR_EXPR, ptr_type_node, exp);}/* Build the address of a runtime type for use in the runtime matching field of the new exception model */static treebuild_eh_type_type_ref (type) tree type;{ const char *typestring; tree exp; if (type == error_mark_node) return error_mark_node; /* peel back references, so they match. */ if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); /* Peel off cv qualifiers. */ type = TYPE_MAIN_VARIANT (type); push_obstacks_nochange (); end_temporary_allocation (); if (flag_rtti) { exp = get_tinfo_fn (type); TREE_USED (exp) = 1; mark_inline_for_output (exp); exp = build1 (ADDR_EXPR, ptr_type_node, exp); } else { typestring = build_overload_name (type, 1, 1); exp = combine_strings (build_string (strlen (typestring)+1, typestring)); exp = build1 (ADDR_EXPR, ptr_type_node, exp); } pop_obstacks (); return (exp);}/* Build a type value for use at runtime for a exp that is thrown or matched against by the exception handling system. */static treebuild_eh_type (exp) tree exp;{ if (flag_rtti) { exp = build_typeid (exp); return build1 (ADDR_EXPR, ptr_type_node, exp); } return build_eh_type_type (TREE_TYPE (exp));}/* This routine is called to mark all the symbols representing runtime type functions in the exception table as haveing been referenced. This will make sure code is emitted for them. Called from finish_file. */void mark_all_runtime_matches () { int x,num; void **ptr; tree exp; num = find_all_handler_type_matches (&ptr); if (num == 0 || ptr == NULL) return; for (x=0; x <num; x++) { exp = (tree) ptr[x]; if (TREE_CODE (exp) == ADDR_EXPR) { exp = TREE_OPERAND (exp, 0); if (TREE_CODE (exp) == FUNCTION_DECL) TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1; } } free (ptr);}/* Build up a call to __cp_pop_exception, to destroy the exception object for the current catch block. HANDLER is either true or false, telling the library whether or not it is being called from an exception handler; if it is, it avoids destroying the object on rethrow. */static treedo_pop_exception (){ tree fn, cleanup; fn = get_identifier ("__cp_pop_exception"); if (IDENTIFIER_GLOBAL_VALUE (fn)) fn = IDENTIFIER_GLOBAL_VALUE (fn); else { /* Declare void __cp_pop_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, tree_cons (NULL_TREE, ptr_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); /* Arrange to do a dynamically scoped cleanup upon exit from this region. */ cleanup = lookup_name (get_identifier ("__exception_info"), 0); cleanup = build_function_call (fn, expr_tree_cons (NULL_TREE, cleanup, NULL_TREE)); return cleanup;}/* This routine creates the cleanup for the current exception. */static voidpush_eh_cleanup (){ int yes; yes = suspend_momentary (); /* All cleanups must last longer than normal. */ expand_decl_cleanup (NULL_TREE, do_pop_exception ()); resume_momentary (yes);}/* Build up a call to terminate on the function obstack, for use as an exception handler. */static treebuild_terminate_handler (){ int yes = suspend_momentary (); tree term = build_function_call (Terminate, NULL_TREE); resume_momentary (yes); return term;}/* Call this to start a catch block. Typename is the typename, and identifier is the variable to place the object in or NULL if the variable doesn't matter. If typename is NULL, that means its a "catch (...)" or catch everything. In that case we don't need to do any type checking. (ie: it ends up as the "else" clause rather than an "else if" clause) */voidexpand_start_catch_block (declspecs, declarator) tree declspecs, declarator;{ tree decl; if (processing_template_decl) { if (declspecs) { decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); pushdecl (decl); decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator), copy_to_permanent (declspecs), NULL_TREE); add_tree (decl); } return; } if (! doing_eh (1)) return; process_start_catch_block (declspecs, declarator);}/* This function performs the expand_start_catch_block functionality for exceptions implemented in the new style. __throw determines whether a handler needs to be called or not, so the handler itself has to do nothing additional. */static void process_start_catch_block (declspecs, declarator) tree declspecs, declarator;{ tree decl = NULL_TREE; tree init; /* Create a binding level for the eh_info and the exception object cleanup. */ pushlevel (0); expand_start_bindings (0); if (declspecs) { decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE); if (decl == NULL_TREE) error ("invalid catch parameter"); } if (decl) start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl))); else start_catch_handler (CATCH_ALL_TYPE); emit_line_note (input_filename, lineno); push_eh_info (); if (decl) { tree exp; tree init_type; /* Make sure we mark the catch param as used, otherwise we'll get a warning about an unused ((anonymous)). */ TREE_USED (decl) = 1; /* Figure out the type that the initializer is. */ init_type = TREE_TYPE (decl); if (TREE_CODE (init_type) != REFERENCE_TYPE && TREE_CODE (init_type) != POINTER_TYPE) init_type = build_reference_type (init_type); exp = get_eh_value (); /* Since pointers are passed by value, initialize a reference to pointer catch parm with the address of the value slot. */ if (TREE_CODE (init_type) == REFERENCE_TYPE && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE) exp = build_unary_op (ADDR_EXPR, exp, 1); exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); push_eh_cleanup (); /* Create a binding level for the parm. */ pushlevel (0); expand_start_bindings (0); init = convert_from_reference (exp); /* If the constructor for the catch parm exits via an exception, we must call terminate. See eh23.C. */ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { /* Generate the copy constructor call directly so we can wrap it. See also expand_default_init. */ init = ocp_convert (TREE_TYPE (decl), init, CONV_IMPLICIT|CONV_FORCE_TEMP, 0); init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init, build_terminate_handler ()); } /* Let `cp_finish_decl' know that this initializer is ok. */ DECL_INITIAL (decl) = init; decl = pushdecl (decl); start_decl_1 (decl); cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING|DIRECT_BIND); } else { push_eh_cleanup (); /* Create a binding level for the parm. */ pushlevel (0); expand_start_bindings (0); /* Fall into the catch all section. */ } emit_line_note (input_filename, lineno);}/* Call this to end a catch block. Its responsible for emitting the code to handle jumping back to the correct place, and for emitting the label to jump to if this catch block didn't match. */voidexpand_end_catch_block (){ if (! doing_eh (1)) return; /* Cleanup the EH parameter. */ expand_end_bindings (getdecls (), kept_level_p (), 0); poplevel (kept_level_p (), 1, 0); /* Cleanup the EH object. */ expand_end_bindings (getdecls (), kept_level_p (), 0); poplevel (kept_level_p (), 1, 0); /* Fall to outside the try statement when done executing handler and we fall off end of handler. This is jump Lresume in the documentation. */ expand_goto (top_label_entry (&caught_return_label_stack)); end_catch_handler ();}/* 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. */voidexpand_start_eh_spec (){ expand_start_try_stmts ();}static voidexpand_end_eh_spec (raises) tree raises;{ tree tmp, fn, decl, types = NULL_TREE; int count = 0; expand_start_all_catch (); expand_start_catch_block (NULL_TREE, NULL_TREE); /* 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; } 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_cplus_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -