static void genericize_if_stmt (tree *stmt_p) { tree stmt, cond, then_, else_; location_t locus = EXPR_LOCATION (*stmt_p); stmt = *stmt_p; cond = IF_COND (stmt); then_ = THEN_CLAUSE (stmt); else_ = ELSE_CLAUSE (stmt); if (!then_) then_ = build_empty_stmt (); if (!else_) else_ = build_empty_stmt (); if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_)) stmt = then_; else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_)) stmt = else_; else stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_); if (CAN_HAVE_LOCATION_P (stmt) && !EXPR_HAS_LOCATION (stmt)) SET_EXPR_LOCATION (stmt, locus); *stmt_p = stmt; }
void xml_location(tree x, FILE *out) { expanded_location l; if (!CAN_HAVE_LOCATION_P(x) && !DECL_P(x)) return; if (EXPR_P(x)) { l = expand_location(EXPR_LOCATION(x)); goto write; } else if (DECL_P(x)) { l = expand_location(DECL_SOURCE_LOCATION(x)); goto write; } return; write: fprintf(out, " location='%s:%d:%d'", filter_built_in(l.file), l.line, l.column); }
static tree c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, bool *maybe_const_itself, bool for_int_const) { tree ret = expr; enum tree_code code = TREE_CODE (expr); enum tree_code_class kind = TREE_CODE_CLASS (code); location_t loc = EXPR_LOCATION (expr); tree op0, op1, op2, op3; tree orig_op0, orig_op1, orig_op2; bool op0_const = true, op1_const = true, op2_const = true; bool op0_const_self = true, op1_const_self = true, op2_const_self = true; bool nowarning = TREE_NO_WARNING (expr); bool unused_p; source_range old_range; /* Constants, declarations, statements, errors, SAVE_EXPRs and anything else not counted as an expression cannot usefully be folded further at this point. */ if (!IS_EXPR_CODE_CLASS (kind) || kind == tcc_statement || code == SAVE_EXPR) return expr; if (IS_EXPR_CODE_CLASS (kind)) old_range = EXPR_LOCATION_RANGE (expr); /* Operands of variable-length expressions (function calls) have already been folded, as have __builtin_* function calls, and such expressions cannot occur in constant expressions. */ if (kind == tcc_vl_exp) { *maybe_const_operands = false; ret = fold (expr); goto out; } if (code == C_MAYBE_CONST_EXPR) { tree pre = C_MAYBE_CONST_EXPR_PRE (expr); tree inner = C_MAYBE_CONST_EXPR_EXPR (expr); if (C_MAYBE_CONST_EXPR_NON_CONST (expr)) *maybe_const_operands = false; if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr)) { *maybe_const_itself = false; inner = c_fully_fold_internal (inner, in_init, maybe_const_operands, maybe_const_itself, true); } if (pre && !in_init) ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner); else ret = inner; goto out; } /* Assignment, increment, decrement, function call and comma operators, and statement expressions, cannot occur in constant expressions if evaluated / outside of sizeof. (Function calls were handled above, though VA_ARG_EXPR is treated like a function call here, and statement expressions are handled through C_MAYBE_CONST_EXPR to avoid folding inside them.) */ switch (code) { case MODIFY_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: case COMPOUND_EXPR: *maybe_const_operands = false; break; case VA_ARG_EXPR: case TARGET_EXPR: case BIND_EXPR: case OBJ_TYPE_REF: *maybe_const_operands = false; ret = fold (expr); goto out; default: break; } /* Fold individual tree codes as appropriate. */ switch (code) { case COMPOUND_LITERAL_EXPR: /* Any non-constancy will have been marked in a containing C_MAYBE_CONST_EXPR; there is no more folding to do here. */ goto out; case COMPONENT_REF: orig_op0 = op0 = TREE_OPERAND (expr, 0); op1 = TREE_OPERAND (expr, 1); op2 = TREE_OPERAND (expr, 2); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op0); if (op0 != orig_op0) ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2); if (ret != expr) { TREE_READONLY (ret) = TREE_READONLY (expr); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); } goto out; case ARRAY_REF: orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); op2 = TREE_OPERAND (expr, 2); op3 = TREE_OPERAND (expr, 3); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op0); op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op1); op1 = decl_constant_value_for_optimization (op1); if (op0 != orig_op0 || op1 != orig_op1) ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3); if (ret != expr) { TREE_READONLY (ret) = TREE_READONLY (expr); TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); } ret = fold (ret); goto out; case COMPOUND_EXPR: case MODIFY_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case POINTER_PLUS_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case TRUNC_MOD_EXPR: case RDIV_EXPR: case EXACT_DIV_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: case BIT_IOR_EXPR: case BIT_XOR_EXPR: case BIT_AND_EXPR: case LT_EXPR: case LE_EXPR: case GT_EXPR: case GE_EXPR: case EQ_EXPR: case NE_EXPR: case COMPLEX_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: case UNORDERED_EXPR: case ORDERED_EXPR: case UNLT_EXPR: case UNLE_EXPR: case UNGT_EXPR: case UNGE_EXPR: case UNEQ_EXPR: /* Binary operations evaluating both arguments (increment and decrement are binary internally in GCC). */ orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op0); if (code != MODIFY_EXPR && code != PREDECREMENT_EXPR && code != PREINCREMENT_EXPR && code != POSTDECREMENT_EXPR && code != POSTINCREMENT_EXPR) op0 = decl_constant_value_for_optimization (op0); /* The RHS of a MODIFY_EXPR was fully folded when building that expression for the sake of conversion warnings. */ if (code != MODIFY_EXPR) op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op1); op1 = decl_constant_value_for_optimization (op1); if (for_int_const && (TREE_CODE (op0) != INTEGER_CST || TREE_CODE (op1) != INTEGER_CST)) goto out; if (op0 != orig_op0 || op1 != orig_op1 || in_init) ret = in_init ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); else ret = fold (expr); if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0) && !TREE_OVERFLOW_P (op1)) overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret); if (code == LSHIFT_EXPR && TREE_CODE (orig_op0) != INTEGER_CST && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE && TREE_CODE (op0) == INTEGER_CST && c_inhibit_evaluation_warnings == 0 && tree_int_cst_sgn (op0) < 0) warning_at (loc, OPT_Wshift_negative_value, "left shift of negative value"); if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR) && TREE_CODE (orig_op1) != INTEGER_CST && TREE_CODE (op1) == INTEGER_CST && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE && c_inhibit_evaluation_warnings == 0) { if (tree_int_cst_sgn (op1) < 0) warning_at (loc, OPT_Wshift_count_negative, (code == LSHIFT_EXPR ? G_("left shift count is negative") : G_("right shift count is negative"))); else if (compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (orig_op0))) >= 0) warning_at (loc, OPT_Wshift_count_overflow, (code == LSHIFT_EXPR ? G_("left shift count >= width of type") : G_("right shift count >= width of type"))); } if (code == LSHIFT_EXPR /* If either OP0 has been folded to INTEGER_CST... */ && ((TREE_CODE (orig_op0) != INTEGER_CST && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE && TREE_CODE (op0) == INTEGER_CST) /* ...or if OP1 has been folded to INTEGER_CST... */ || (TREE_CODE (orig_op1) != INTEGER_CST && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE && TREE_CODE (op1) == INTEGER_CST)) && c_inhibit_evaluation_warnings == 0) /* ...then maybe we can detect an overflow. */ maybe_warn_shift_overflow (loc, op0, op1); if ((code == TRUNC_DIV_EXPR || code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR || code == EXACT_DIV_EXPR || code == TRUNC_MOD_EXPR) && TREE_CODE (orig_op1) != INTEGER_CST && TREE_CODE (op1) == INTEGER_CST && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE) && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE) warn_for_div_by_zero (loc, op1); goto out; case INDIRECT_REF: case FIX_TRUNC_EXPR: case FLOAT_EXPR: CASE_CONVERT: case ADDR_SPACE_CONVERT_EXPR: case VIEW_CONVERT_EXPR: case NON_LVALUE_EXPR: case NEGATE_EXPR: case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: case ADDR_EXPR: case CONJ_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: /* Unary operations. */ orig_op0 = op0 = TREE_OPERAND (expr, 0); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op0); if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR) op0 = decl_constant_value_for_optimization (op0); if (for_int_const && TREE_CODE (op0) != INTEGER_CST) goto out; /* ??? Cope with user tricks that amount to offsetof. The middle-end is not prepared to deal with them if they occur in initializers. */ if (op0 != orig_op0 && code == ADDR_EXPR && (op1 = get_base_address (op0)) != NULL_TREE && INDIRECT_REF_P (op1) && TREE_CONSTANT (TREE_OPERAND (op1, 0))) ret = fold_convert_loc (loc, TREE_TYPE (expr), fold_offsetof_1 (op0)); else if (op0 != orig_op0 || in_init) ret = in_init ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0) : fold_build1_loc (loc, code, TREE_TYPE (expr), op0); else ret = fold (expr); if (code == INDIRECT_REF && ret != expr && INDIRECT_REF_P (ret)) { TREE_READONLY (ret) = TREE_READONLY (expr); TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); } switch (code) { case FIX_TRUNC_EXPR: case FLOAT_EXPR: CASE_CONVERT: /* Don't warn about explicit conversions. We will already have warned about suspect implicit conversions. */ break; default: if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0)) overflow_warning (EXPR_LOCATION (expr), ret); break; } goto out; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: /* Binary operations not necessarily evaluating both arguments. */ orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, for_int_const); STRIP_TYPE_NOPS (op0); unused_p = (op0 == (code == TRUTH_ANDIF_EXPR ? truthvalue_false_node : truthvalue_true_node)); c_disable_warnings (unused_p); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, for_int_const); STRIP_TYPE_NOPS (op1); c_enable_warnings (unused_p); if (for_int_const && (TREE_CODE (op0) != INTEGER_CST /* Require OP1 be an INTEGER_CST only if it's evaluated. */ || (!unused_p && TREE_CODE (op1) != INTEGER_CST))) goto out; if (op0 != orig_op0 || op1 != orig_op1 || in_init) ret = in_init ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); else ret = fold (expr); *maybe_const_operands &= op0_const; *maybe_const_itself &= op0_const_self; if (!(flag_isoc99 && op0_const && op0_const_self && (code == TRUTH_ANDIF_EXPR ? op0 == truthvalue_false_node : op0 == truthvalue_true_node))) *maybe_const_operands &= op1_const; if (!(op0_const && op0_const_self && (code == TRUTH_ANDIF_EXPR ? op0 == truthvalue_false_node : op0 == truthvalue_true_node))) *maybe_const_itself &= op1_const_self; goto out; case COND_EXPR: orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); orig_op2 = op2 = TREE_OPERAND (expr, 2); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self, for_int_const); STRIP_TYPE_NOPS (op0); c_disable_warnings (op0 == truthvalue_false_node); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, for_int_const); STRIP_TYPE_NOPS (op1); c_enable_warnings (op0 == truthvalue_false_node); c_disable_warnings (op0 == truthvalue_true_node); op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self, for_int_const); STRIP_TYPE_NOPS (op2); c_enable_warnings (op0 == truthvalue_true_node); if (for_int_const && (TREE_CODE (op0) != INTEGER_CST /* Only the evaluated operand must be an INTEGER_CST. */ || (op0 == truthvalue_true_node ? TREE_CODE (op1) != INTEGER_CST : TREE_CODE (op2) != INTEGER_CST))) goto out; if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); else ret = fold (expr); *maybe_const_operands &= op0_const; *maybe_const_itself &= op0_const_self; if (!(flag_isoc99 && op0_const && op0_const_self && op0 == truthvalue_false_node)) *maybe_const_operands &= op1_const; if (!(op0_const && op0_const_self && op0 == truthvalue_false_node)) *maybe_const_itself &= op1_const_self; if (!(flag_isoc99 && op0_const && op0_const_self && op0 == truthvalue_true_node)) *maybe_const_operands &= op2_const; if (!(op0_const && op0_const_self && op0 == truthvalue_true_node)) *maybe_const_itself &= op2_const_self; goto out; case VEC_COND_EXPR: orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); orig_op2 = op2 = TREE_OPERAND (expr, 2); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op0); op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op1); op2 = c_fully_fold_internal (op2, in_init, maybe_const_operands, maybe_const_itself, for_int_const); STRIP_TYPE_NOPS (op2); if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); else ret = fold (expr); goto out; case EXCESS_PRECISION_EXPR: /* Each case where an operand with excess precision may be encountered must remove the EXCESS_PRECISION_EXPR around inner operands and possibly put one around the whole expression or possibly convert to the semantic type (which c_fully_fold does); we cannot tell at this stage which is appropriate in any particular case. */ gcc_unreachable (); default: /* Various codes may appear through folding built-in functions and their arguments. */ goto out; } out: /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks have been done by this point, so remove them again. */ nowarning |= TREE_NO_WARNING (ret); STRIP_TYPE_NOPS (ret); if (nowarning && !TREE_NO_WARNING (ret)) { if (!CAN_HAVE_LOCATION_P (ret)) ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret); TREE_NO_WARNING (ret) = 1; } if (ret != expr) { protected_set_expr_location (ret, loc); if (IS_EXPR_CODE_CLASS (kind)) set_source_range (ret, old_range.m_start, old_range.m_finish); } return ret; }