+/* Return true if operation OP may trap. FP_OPERATION is true if OP is applied
+ on floating-point values. HONOR_TRAPV is true if OP is applied on integer
+ type operands that may trap. If OP is a division operator, DIVISOR contains
+ the value of the divisor. */
+
+bool
+operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
+ tree divisor)
+{
+ bool honor_nans = (fp_operation && flag_trapping_math
+ && !flag_finite_math_only);
+ bool honor_snans = fp_operation && flag_signaling_nans != 0;
+ bool handled;
+
+ if (TREE_CODE_CLASS (op) != tcc_comparison
+ && TREE_CODE_CLASS (op) != tcc_unary
+ && TREE_CODE_CLASS (op) != tcc_binary)
+ return false;
+
+ return operation_could_trap_helper_p (op, fp_operation, honor_trapv,
+ honor_nans, honor_snans, divisor,
+ &handled);
+}
+
+/* Return true if EXPR can trap, as in dereferencing an invalid pointer
+ location or floating point arithmetic. C.f. the rtl version, may_trap_p.
+ This routine expects only GIMPLE lhs or rhs input. */
+
+bool
+tree_could_trap_p (tree expr)
+{
+ enum tree_code code;
+ bool fp_operation = false;
+ bool honor_trapv = false;
+ tree t, base, div = NULL_TREE;
+
+ if (!expr)
+ return false;
+
+ code = TREE_CODE (expr);
+ t = TREE_TYPE (expr);
+
+ if (t)
+ {
+ if (COMPARISON_CLASS_P (expr))
+ fp_operation = FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ else
+ fp_operation = FLOAT_TYPE_P (t);
+ honor_trapv = INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t);
+ }
+
+ if (TREE_CODE_CLASS (code) == tcc_binary)
+ div = TREE_OPERAND (expr, 1);
+ if (operation_could_trap_p (code, fp_operation, honor_trapv, div))
+ return true;
+
+ restart:
+ switch (code)
+ {
+ case TARGET_MEM_REF:
+ /* For TARGET_MEM_REFs use the information based on the original
+ reference. */
+ expr = TMR_ORIGINAL (expr);
+ code = TREE_CODE (expr);
+ goto restart;
+
+ case COMPONENT_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case BIT_FIELD_REF:
+ case VIEW_CONVERT_EXPR:
+ case WITH_SIZE_EXPR:
+ expr = TREE_OPERAND (expr, 0);
+ code = TREE_CODE (expr);
+ goto restart;
+
+ case ARRAY_RANGE_REF:
+ base = TREE_OPERAND (expr, 0);
+ if (tree_could_trap_p (base))
+ return true;
+
+ if (TREE_THIS_NOTRAP (expr))
+ return false;
+
+ return !range_in_array_bounds_p (expr);
+
+ case ARRAY_REF:
+ base = TREE_OPERAND (expr, 0);
+ if (tree_could_trap_p (base))
+ return true;
+
+ if (TREE_THIS_NOTRAP (expr))
+ return false;
+
+ return !in_array_bounds_p (expr);
+
+ case INDIRECT_REF:
+ case ALIGN_INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
+ return !TREE_THIS_NOTRAP (expr);
+
+ case ASM_EXPR:
+ return TREE_THIS_VOLATILE (expr);
+
+
+ case CALL_EXPR:
+ t = get_callee_fndecl (expr);
+ /* Assume that calls to weak functions may trap. */
+ if (!t || !DECL_P (t) || DECL_WEAK (t))
+ return true;
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+
+/* Helper for stmt_could_throw_p. Return true if STMT (assumed to be a
+ an assignment or a conditional) may throw. */
+
+static bool
+stmt_could_throw_1_p (gimple stmt)
+{
+ enum tree_code code = gimple_expr_code (stmt);
+ bool honor_nans = false;
+ bool honor_snans = false;
+ bool fp_operation = false;
+ bool honor_trapv = false;
+ tree t;
+ size_t i;
+ bool handled, ret;
+
+ if (TREE_CODE_CLASS (code) == tcc_comparison
+ || TREE_CODE_CLASS (code) == tcc_unary
+ || TREE_CODE_CLASS (code) == tcc_binary)
+ {
+ t = gimple_expr_type (stmt);
+ fp_operation = FLOAT_TYPE_P (t);
+ if (fp_operation)
+ {
+ honor_nans = flag_trapping_math && !flag_finite_math_only;
+ honor_snans = flag_signaling_nans != 0;
+ }
+ else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
+ honor_trapv = true;
+ }
+
+ /* Check if the main expression may trap. */
+ t = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) : NULL;
+ ret = operation_could_trap_helper_p (code, fp_operation, honor_trapv,
+ honor_nans, honor_snans, t,
+ &handled);
+ if (handled)
+ return ret;
+
+ /* If the expression does not trap, see if any of the individual operands may
+ trap. */
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ if (tree_could_trap_p (gimple_op (stmt, i)))
+ return true;
+
+ return false;
+}
+
+
+/* Return true if statement STMT could throw an exception. */
+
+bool
+stmt_could_throw_p (gimple stmt)
+{
+ enum gimple_code code;
+
+ if (!flag_exceptions)
+ return false;
+
+ /* The only statements that can throw an exception are assignments,
+ conditionals, calls and asms. */
+ code = gimple_code (stmt);
+ if (code != GIMPLE_ASSIGN
+ && code != GIMPLE_COND
+ && code != GIMPLE_CALL
+ && code != GIMPLE_ASM)
+ return false;
+
+ /* If exceptions can only be thrown by function calls and STMT is not a
+ GIMPLE_CALL, the statement cannot throw. */
+ if (!flag_non_call_exceptions && code != GIMPLE_CALL)
+ return false;
+
+ if (code == GIMPLE_ASSIGN || code == GIMPLE_COND)
+ return stmt_could_throw_1_p (stmt);
+ else if (is_gimple_call (stmt))
+ {
+ tree t = gimple_call_fndecl (stmt);
+
+ /* Assume that calls to weak functions may trap. */
+ if (!t || !DECL_P (t) || DECL_WEAK (t))
+ return true;
+
+ return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
+ }
+ else if (gimple_code (stmt) == GIMPLE_ASM)
+ return (gimple_asm_volatile_p (stmt));
+ else
+ gcc_unreachable ();
+
+ return false;
+}
+
+
+/* Return true if expression T could throw an exception. */
+