static tree do_end_catch (tree type) { tree fn, cleanup; fn = get_identifier ("__cxa_end_catch"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_end_catch (). This can throw if the destructor for the exception throws. */ fn = push_void_library_fn (fn, void_list_node, 0); /* Create its transactional-memory equivalent. */ if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_end_catch"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = push_void_library_fn (fn2, void_list_node, ECF_TM_PURE); record_tm_replacement (fn, fn2); } } cleanup = cp_build_function_call_vec (fn, NULL, tf_warning_or_error); TREE_NOTHROW (cleanup) = dtor_nothrow (type); return cleanup; }
static tree do_begin_catch (void) { tree fn; fn = get_identifier ("__cxa_begin_catch"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_begin_catch (void *) throw(). */ fn = declare_library_fn (fn, ptr_type_node, ptr_type_node, ECF_NOTHROW); /* Create its transactional-memory equivalent. */ if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_begin_catch"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = declare_library_fn (fn2, ptr_type_node, ptr_type_node, ECF_NOTHROW | ECF_TM_PURE); record_tm_replacement (fn, fn2); } } return cp_build_function_call_nary (fn, tf_warning_or_error, build_exc_ptr (), NULL_TREE); }
static tree do_allocate_exception (tree type) { tree fn; fn = get_identifier ("__cxa_allocate_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void *__cxa_allocate_exception(size_t) throw(). */ fn = declare_library_fn (fn, ptr_type_node, size_type_node, ECF_NOTHROW | ECF_MALLOC); if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_allocate_exception"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = declare_library_fn (fn2, ptr_type_node, size_type_node, ECF_NOTHROW | ECF_MALLOC | ECF_TM_PURE); record_tm_replacement (fn, fn2); } } return cp_build_function_call_nary (fn, tf_warning_or_error, size_in_bytes (type), NULL_TREE); }
static tree do_free_exception (tree ptr) { tree fn; fn = get_identifier ("__cxa_free_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_free_exception (void *) throw(). */ fn = declare_library_fn (fn, void_type_node, ptr_type_node, ECF_NOTHROW | ECF_LEAF); if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_free_exception"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = declare_library_fn (fn2, void_type_node, ptr_type_node, ECF_NOTHROW | ECF_LEAF | ECF_TM_PURE); record_tm_replacement (fn, fn2); } } return cp_build_function_call_nary (fn, tf_warning_or_error, ptr, NULL_TREE); }
static tree throw_bad_cast (void) { tree fn = get_identifier ("__cxa_bad_cast"); if (!get_global_value_if_present (fn, &fn)) fn = push_throw_library_fn (fn, build_function_type (ptr_type_node, void_list_node)); return build_cxx_call (fn, NULL_TREE); }
static tree do_free_exception (tree ptr) { tree fn; fn = get_identifier ("__cxa_free_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_free_exception (void *) throw(). */ fn = declare_nothrow_library_fn (fn, void_type_node, ptr_type_node); } return cp_build_function_call_nary (fn, tf_warning_or_error, ptr, NULL_TREE); }
static tree throw_bad_typeid (void) { tree fn = get_identifier ("__cxa_bad_typeid"); if (!get_global_value_if_present (fn, &fn)) { tree t; t = build_reference_type (const_type_info_type_node); t = build_function_type (t, void_list_node); fn = push_throw_library_fn (fn, t); } return build_cxx_call (fn, NULL_TREE); }
static tree do_free_exception (tree ptr) { tree fn; fn = get_identifier ("__cxa_free_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_free_exception (void *). */ fn = push_void_library_fn (fn, tree_cons (NULL_TREE, ptr_type_node, void_list_node)); } return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE)); }
static tree do_get_exception_ptr (void) { tree fn; fn = get_identifier ("__cxa_get_exception_ptr"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_get_exception_ptr (void *) throw(). */ fn = declare_library_fn (fn, ptr_type_node, ptr_type_node, ECF_NOTHROW | ECF_PURE | ECF_LEAF | ECF_TM_PURE); } return cp_build_function_call_nary (fn, tf_warning_or_error, build_exc_ptr (), NULL_TREE); }
static tree do_allocate_exception (tree type) { tree fn; fn = get_identifier ("__cxa_allocate_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void *__cxa_allocate_exception(size_t). */ tree tmp = tree_cons (NULL_TREE, size_type_node, void_list_node); fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); } return build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE)); }
static tree do_begin_catch (void) { tree fn; fn = get_identifier ("__cxa_begin_catch"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_begin_catch (void *) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node); } return cp_build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), NULL_TREE), tf_warning_or_error); }
static tree do_begin_catch (void) { tree fn; fn = get_identifier ("__cxa_begin_catch"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_begin_catch (void *). */ tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); } return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), NULL_TREE)); }
static tree do_allocate_exception (tree type) { tree fn; fn = get_identifier ("__cxa_allocate_exception"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void *__cxa_allocate_exception(size_t) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, size_type_node); } return cp_build_function_call (fn, tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE), tf_warning_or_error); }
static tree do_get_exception_ptr (void) { tree fn; fn = get_identifier ("__cxa_get_exception_ptr"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_get_exception_ptr (void *) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node); if (flag_tm) apply_tm_attr (fn, get_identifier ("transaction_pure")); } return cp_build_function_call_nary (fn, tf_warning_or_error, build_exc_ptr (), NULL_TREE); }
static tree do_end_catch (tree type) { tree fn, cleanup; fn = get_identifier ("__cxa_end_catch"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_end_catch (). */ fn = push_void_library_fn (fn, void_list_node); /* This can throw if the destructor for the exception throws. */ TREE_NOTHROW (fn) = 0; } cleanup = build_function_call (fn, NULL_TREE); TREE_NOTHROW (cleanup) = dtor_nothrow (type); return cleanup; }
static tree /* APPLE LOCAL radar 2848255 */ do_begin_catch (tree type) { tree fn; /* APPLE LOCAL begin radar 2848255 */ if (c_dialect_objc () && objc2_valid_objc_catch_type (type)) fn = get_identifier ("objc_begin_catch"); else fn = get_identifier ("__cxa_begin_catch"); /* APPLE LOCAL end radar 2848255 */ if (!get_global_value_if_present (fn, &fn)) { /* Declare void* __cxa_begin_catch (void *). */ tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp)); } return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (), NULL_TREE)); }
static tree do_end_catch (tree type) { tree fn, cleanup; /* APPLE LOCAL begin radar 2848255 */ if (c_dialect_objc () && objc2_valid_objc_catch_type (type)) fn = get_identifier ("objc_end_catch"); else fn = get_identifier ("__cxa_end_catch"); /* APPLE LOCAL end radar 2848255 */ if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_end_catch (). */ fn = push_void_library_fn (fn, void_list_node); /* This can throw if the destructor for the exception throws. */ TREE_NOTHROW (fn) = 0; } cleanup = build_function_call (fn, NULL_TREE); TREE_NOTHROW (cleanup) = dtor_nothrow (type); return cleanup; }
tree build_throw (tree exp) { tree fn; if (exp == error_mark_node) return exp; if (processing_template_decl) { if (cfun) current_function_returns_abnormally = 1; exp = build_min (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; } if (exp == null_node) warning (0, "throwing NULL, which has integral, not pointer type"); if (exp != NULL_TREE) { if (!is_admissible_throw_operand_or_catch_parameter (exp, true)) return error_mark_node; } if (! doing_eh ()) return error_mark_node; if (exp && decl_is_java_type (TREE_TYPE (exp), 1)) { tree fn = get_identifier ("_Jv_Throw"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void _Jv_Throw (void *). */ tree tmp; tmp = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE); fn = push_throw_library_fn (fn, tmp); } else if (really_overloaded_fn (fn)) { error ("%qD should never be overloaded", fn); return error_mark_node; } fn = OVL_CURRENT (fn); exp = cp_build_function_call_nary (fn, tf_warning_or_error, exp, NULL_TREE); } else if (exp) { tree throw_type; tree temp_type; tree cleanup; tree object, ptr; tree tmp; tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) { tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); cleanup_type = build_pointer_type (tmp); } fn = get_identifier ("__cxa_throw"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ /* ??? Second argument is supposed to be "std::type_info*". */ tmp = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, cleanup_type, NULL_TREE); fn = push_throw_library_fn (fn, tmp); if (flag_tm) { tree fn2 = get_identifier ("_ITM_cxa_throw"); if (!get_global_value_if_present (fn2, &fn2)) fn2 = push_throw_library_fn (fn2, tmp); apply_tm_attr (fn2, get_identifier ("transaction_pure")); record_tm_replacement (fn, fn2); } } /* [except.throw] A throw-expression initializes a temporary object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function return T" to "pointer to T" or "pointer to function returning T" respectively. */ temp_type = is_bitfield_expr_with_lowered_type (exp); if (!temp_type) temp_type = cv_unqualified (type_decays_to (TREE_TYPE (exp))); /* OK, this is kind of wacky. The standard 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. Since there could be temps in the expression, we need to handle that, too. We also expand the call to __cxa_allocate_exception first (which doesn't matter, since it can't throw). */ /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); CLEANUP_EH_ONLY (allocate_expr) = 1; object = build_nop (build_pointer_type (temp_type), ptr); object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error); /* And initialize the exception object. */ if (CLASS_TYPE_P (temp_type)) { int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING; vec<tree, va_gc> *exp_vec; /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes treated as an rvalue for the purposes of overload resolution to favor move constructors over copy constructors. */ if (/* Must be a local, automatic variable. */ VAR_P (exp) && DECL_CONTEXT (exp) == current_function_decl && ! TREE_STATIC (exp) /* The variable must not have the `volatile' qualifier. */ && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE)) flags = flags | LOOKUP_PREFER_RVALUE; /* Call the copy constructor. */ exp_vec = make_tree_vector_single (exp); exp = (build_special_member_call (object, complete_ctor_identifier, &exp_vec, TREE_TYPE (object), flags, tf_warning_or_error)); release_tree_vector (exp_vec); if (exp == error_mark_node) { error (" in thrown expression"); return error_mark_node; } } else { tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); } /* Mark any cleanups from the initialization as MUST_NOT_THROW, since they are run after the exception object is initialized. */ cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); /* Force all the cleanups to be evaluated here so that we don't have to do them during unwinding. */ exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); cleanup = NULL_TREE; if (type_build_dtor_call (TREE_TYPE (object))) { tree fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)), complete_dtor_identifier, 0); fn = BASELINK_FUNCTIONS (fn); mark_used (fn); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object))) { cxx_mark_addressable (fn); /* Pretend it's a normal function. */ cleanup = build1 (ADDR_EXPR, cleanup_type, fn); } } if (cleanup == NULL_TREE) cleanup = build_int_cst (cleanup_type, 0); /* ??? Indicate that this function call throws throw_type. */ tmp = cp_build_function_call_nary (fn, tf_warning_or_error, ptr, throw_type, cleanup, NULL_TREE); /* Tack on the initialization stuff. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (tmp), exp, tmp); } else { /* Rethrow current exception. */ tree fn = get_identifier ("__cxa_rethrow"); if (!get_global_value_if_present (fn, &fn)) { /* Declare void __cxa_rethrow (void). */ fn = push_throw_library_fn (fn, build_function_type_list (void_type_node, NULL_TREE)); } if (flag_tm) apply_tm_attr (fn, get_identifier ("transaction_pure")); /* ??? Indicate that this function call allows exceptions of the type of the enclosing catch block (if known). */ exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error); } exp = build1 (THROW_EXPR, void_type_node, exp); SET_EXPR_LOCATION (exp, input_location); return exp; }