tree expand_array_notation_exprs (tree t) { enum tree_code code; bool is_expr; location_t loc = UNKNOWN_LOCATION; if (!t) return t; loc = EXPR_LOCATION (t); code = TREE_CODE (t); is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)); switch (code) { case ERROR_MARK: case IDENTIFIER_NODE: case VOID_CST: case INTEGER_CST: case REAL_CST: case FIXED_CST: case STRING_CST: case BLOCK: case PLACEHOLDER_EXPR: case FIELD_DECL: case VOID_TYPE: case REAL_TYPE: case SSA_NAME: case LABEL_DECL: case RESULT_DECL: case VAR_DECL: case PARM_DECL: case NON_LVALUE_EXPR: case NOP_EXPR: case ADDR_EXPR: case ARRAY_REF: case BIT_FIELD_REF: case VECTOR_CST: case COMPLEX_CST: return t; case INIT_EXPR: case MODIFY_EXPR: if (contains_array_notation_expr (t)) t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR, TREE_OPERAND (t, 1), tf_warning_or_error); return t; case MODOP_EXPR: if (contains_array_notation_expr (t) && !processing_template_decl) t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)), TREE_OPERAND (t, 2), tf_warning_or_error); return t; case CONSTRUCTOR: return t; case BIND_EXPR: { BIND_EXPR_BODY (t) = expand_array_notation_exprs (BIND_EXPR_BODY (t)); return t; } case DECL_EXPR: if (contains_array_notation_expr (t)) { tree x = DECL_EXPR_DECL (t); if (DECL_INITIAL (x)) { location_t loc = DECL_SOURCE_LOCATION (x); tree lhs = x; tree rhs = DECL_INITIAL (x); DECL_INITIAL (x) = NULL; tree new_modify_expr = build_modify_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR, loc, rhs, TREE_TYPE(rhs)); t = expand_array_notation_exprs (new_modify_expr); } } return t; case STATEMENT_LIST: { tree_stmt_iterator i; for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) *tsi_stmt_ptr (i) = expand_array_notation_exprs (*tsi_stmt_ptr (i)); return t; } case OMP_PARALLEL: case OMP_TASK: case OMP_FOR: case OMP_SINGLE: case OMP_SECTION: case OMP_SECTIONS: case OMP_MASTER: case OMP_TASKGROUP: case OMP_ORDERED: case OMP_CRITICAL: case OMP_ATOMIC: case OMP_CLAUSE: case TARGET_EXPR: case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case POINTER_TYPE: case ARRAY_TYPE: case RECORD_TYPE: case METHOD_TYPE: return t; case RETURN_EXPR: if (contains_array_notation_expr (t)) t = expand_return_expr (t); return t; case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: case AGGR_INIT_EXPR: case CALL_EXPR: t = expand_unary_array_notation_exprs (t); return t; case CONVERT_EXPR: case CLEANUP_POINT_EXPR: case EXPR_STMT: TREE_OPERAND (t, 0) = expand_array_notation_exprs (TREE_OPERAND (t, 0)); /* It is not necessary to wrap error_mark_node in EXPR_STMT. */ if (TREE_OPERAND (t, 0) == error_mark_node) return TREE_OPERAND (t, 0); return t; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: case TRUTH_NOT_EXPR: case COND_EXPR: t = cp_expand_cond_array_notations (t); if (TREE_CODE (t) == COND_EXPR) { COND_EXPR_THEN (t) = expand_array_notation_exprs (COND_EXPR_THEN (t)); COND_EXPR_ELSE (t) = expand_array_notation_exprs (COND_EXPR_ELSE (t)); } return t; case FOR_STMT: if (contains_array_notation_expr (FOR_COND (t))) { error_at (EXPR_LOCATION (FOR_COND (t)), "array notation cannot be used in a condition for " "a for-loop"); return error_mark_node; } /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking keywords. */ if (TREE_CODE (t) == FOR_STMT) { FOR_BODY (t) = expand_array_notation_exprs (FOR_BODY (t)); FOR_EXPR (t) = expand_array_notation_exprs (FOR_EXPR (t)); } else t = expand_array_notation_exprs (t); return t; case IF_STMT: t = cp_expand_cond_array_notations (t); /* If the above function added some extra instructions above the original if statement, then we can't assume it is still IF_STMT so we have to check again. */ if (TREE_CODE (t) == IF_STMT) { if (THEN_CLAUSE (t)) THEN_CLAUSE (t) = expand_array_notation_exprs (THEN_CLAUSE (t)); if (ELSE_CLAUSE (t)) ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t)); } else t = expand_array_notation_exprs (t); return t; case SWITCH_STMT: if (contains_array_notation_expr (SWITCH_STMT_COND (t))) { error_at (EXPR_LOCATION (SWITCH_STMT_COND (t)), "array notation cannot be used as a condition for " "switch statement"); return error_mark_node; } if (SWITCH_STMT_BODY (t)) SWITCH_STMT_BODY (t) = expand_array_notation_exprs (SWITCH_STMT_BODY (t)); return t; case WHILE_STMT: if (contains_array_notation_expr (WHILE_COND (t))) { if (EXPR_LOCATION (WHILE_COND (t)) != UNKNOWN_LOCATION) loc = EXPR_LOCATION (WHILE_COND (t)); error_at (loc, "array notation cannot be used as a condition for " "while statement"); return error_mark_node; } if (WHILE_BODY (t)) WHILE_BODY (t) = expand_array_notation_exprs (WHILE_BODY (t)); return t; case DO_STMT: if (contains_array_notation_expr (DO_COND (t))) { error_at (EXPR_LOCATION (DO_COND (t)), "array notation cannot be used as a condition for a " "do-while statement"); return error_mark_node; } if (DO_BODY (t)) DO_BODY (t) = expand_array_notation_exprs (DO_BODY (t)); return t; default: if (is_expr) { int i, len; /* Walk over all the sub-trees of this operand. */ len = TREE_CODE_LENGTH (code); /* Go through the subtrees. We need to do this in forward order so that the scope of a FOR_EXPR is handled properly. */ for (i = 0; i < len; ++i) TREE_OPERAND (t, i) = expand_array_notation_exprs (TREE_OPERAND (t, i)); } return t; } return t; }
static void dequeue_and_dump (dump_info_p di) { dump_queue_p dq; splay_tree_node stn; dump_node_info_p dni; tree t; unsigned int index; enum tree_code code; enum tree_code_class code_class; const char* code_name; /* Get the next node from the queue. */ dq = di->queue; stn = dq->node; t = (tree) stn->key; dni = (dump_node_info_p) stn->value; index = dni->index; /* Remove the node from the queue, and put it on the free list. */ di->queue = dq->next; if (!di->queue) di->queue_end = 0; dq->next = di->free_list; di->free_list = dq; /* Print the node index. */ dump_index (di, index); /* And the type of node this is. */ if (dni->binfo_p) code_name = "binfo"; else code_name = tree_code_name[(int) TREE_CODE (t)]; fprintf (di->stream, "%-16s ", code_name); di->column = 25; /* Figure out what kind of node this is. */ code = TREE_CODE (t); code_class = TREE_CODE_CLASS (code); /* Although BINFOs are TREE_VECs, we dump them specially so as to be more informative. */ if (dni->binfo_p) { unsigned ix; tree base; VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t); dump_child ("type", BINFO_TYPE (t)); if (BINFO_VIRTUAL_P (t)) dump_string_field (di, "spec", "virt"); dump_int (di, "bases", BINFO_N_BASE_BINFOS (t)); for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++) { tree access = (accesses ? VEC_index (tree, accesses, ix) : access_public_node); const char *string = NULL; if (access == access_public_node) string = "pub"; else if (access == access_protected_node) string = "prot"; else if (access == access_private_node) string = "priv"; else gcc_unreachable (); dump_string_field (di, "accs", string); queue_and_dump_index (di, "binf", base, DUMP_BINFO); } goto done; } /* We can knock off a bunch of expression nodes in exactly the same way. */ if (IS_EXPR_CODE_CLASS (code_class)) { /* If we're dumping children, dump them now. */ queue_and_dump_type (di, t); switch (code_class) { case tcc_unary: dump_child ("op 0", TREE_OPERAND (t, 0)); break; case tcc_binary: case tcc_comparison: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case tcc_expression: case tcc_reference: case tcc_statement: case tcc_vl_exp: /* These nodes are handled explicitly below. */ break; default: gcc_unreachable (); } } else if (DECL_P (t)) { expanded_location xloc; /* All declarations have names. */ if (DECL_NAME (t)) dump_child ("name", DECL_NAME (t)); if (DECL_ASSEMBLER_NAME_SET_P (t) && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t)) dump_child ("mngl", DECL_ASSEMBLER_NAME (t)); if (DECL_ABSTRACT_ORIGIN (t)) dump_child ("orig", DECL_ABSTRACT_ORIGIN (t)); /* And types. */ queue_and_dump_type (di, t); dump_child ("scpe", DECL_CONTEXT (t)); /* And a source position. */ xloc = expand_location (DECL_SOURCE_LOCATION (t)); if (xloc.file) { const char *filename = lbasename (xloc.file); dump_maybe_newline (di); fprintf (di->stream, "srcp: %s:%-6d ", filename, xloc.line); di->column += 6 + strlen (filename) + 8; } /* And any declaration can be compiler-generated. */ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON) && DECL_ARTIFICIAL (t)) dump_string_field (di, "note", "artificial"); if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL)) dump_child ("chain", DECL_CHAIN (t)); } else if (code_class == tcc_type) { /* All types have qualifiers. */ int quals = lang_hooks.tree_dump.type_quals (t); if (quals != TYPE_UNQUALIFIED) { fprintf (di->stream, "qual: %c%c%c ", (quals & TYPE_QUAL_CONST) ? 'c' : ' ', (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ', (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' '); di->column += 14; } /* All types have associated declarations. */ dump_child ("name", TYPE_NAME (t)); /* All types have a main variant. */ if (TYPE_MAIN_VARIANT (t) != t) dump_child ("unql", TYPE_MAIN_VARIANT (t)); /* And sizes. */ dump_child ("size", TYPE_SIZE (t)); /* All types have alignments. */ dump_int (di, "algn", TYPE_ALIGN (t)); } else if (code_class == tcc_constant) /* All constants can have types. */ queue_and_dump_type (di, t); /* Give the language-specific code a chance to print something. If it's completely taken care of things, don't bother printing anything more ourselves. */ if (lang_hooks.tree_dump.dump_tree (di, t)) goto done; /* Now handle the various kinds of nodes. */ switch (code) { int i; case IDENTIFIER_NODE: dump_string_field (di, "strg", IDENTIFIER_POINTER (t)); dump_int (di, "lngt", IDENTIFIER_LENGTH (t)); break; case TREE_LIST: dump_child ("purp", TREE_PURPOSE (t)); dump_child ("valu", TREE_VALUE (t)); dump_child ("chan", TREE_CHAIN (t)); break; case STATEMENT_LIST: { tree_stmt_iterator it; for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, tsi_stmt (it)); } } break; case TREE_VEC: dump_int (di, "lngt", TREE_VEC_LENGTH (t)); for (i = 0; i < TREE_VEC_LENGTH (t); ++i) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, TREE_VEC_ELT (t, i)); } break; case INTEGER_TYPE: case ENUMERAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_child ("min", TYPE_MIN_VALUE (t)); dump_child ("max", TYPE_MAX_VALUE (t)); if (code == ENUMERAL_TYPE) dump_child ("csts", TYPE_VALUES (t)); break; case REAL_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); break; case FIXED_POINT_TYPE: dump_int (di, "prec", TYPE_PRECISION (t)); dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed"); dump_string_field (di, "saturating", TYPE_SATURATING (t) ? "saturating": "non-saturating"); break; case POINTER_TYPE: dump_child ("ptd", TREE_TYPE (t)); break; case REFERENCE_TYPE: dump_child ("refd", TREE_TYPE (t)); break; case METHOD_TYPE: dump_child ("clas", TYPE_METHOD_BASETYPE (t)); /* Fall through. */ case FUNCTION_TYPE: dump_child ("retn", TREE_TYPE (t)); dump_child ("prms", TYPE_ARG_TYPES (t)); break; case ARRAY_TYPE: dump_child ("elts", TREE_TYPE (t)); dump_child ("domn", TYPE_DOMAIN (t)); break; case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (t) == RECORD_TYPE) dump_string_field (di, "tag", "struct"); else dump_string_field (di, "tag", "union"); dump_child ("flds", TYPE_FIELDS (t)); dump_child ("fncs", TYPE_METHODS (t)); queue_and_dump_index (di, "binf", TYPE_BINFO (t), DUMP_BINFO); break; case CONST_DECL: dump_child ("cnst", DECL_INITIAL (t)); break; case DEBUG_EXPR_DECL: dump_int (di, "-uid", DEBUG_TEMP_UID (t)); /* Fall through. */ case VAR_DECL: case PARM_DECL: case FIELD_DECL: case RESULT_DECL: if (TREE_CODE (t) == PARM_DECL) dump_child ("argt", DECL_ARG_TYPE (t)); else dump_child ("init", DECL_INITIAL (t)); dump_child ("size", DECL_SIZE (t)); dump_int (di, "algn", DECL_ALIGN (t)); if (TREE_CODE (t) == FIELD_DECL) { if (DECL_FIELD_OFFSET (t)) dump_child ("bpos", bit_position (t)); } else if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL) { dump_int (di, "used", TREE_USED (t)); if (DECL_REGISTER (t)) dump_string_field (di, "spec", "register"); } break; case FUNCTION_DECL: dump_child ("args", DECL_ARGUMENTS (t)); if (DECL_EXTERNAL (t)) dump_string_field (di, "body", "undefined"); if (TREE_PUBLIC (t)) dump_string_field (di, "link", "extern"); else dump_string_field (di, "link", "static"); if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t)) dump_child ("body", DECL_SAVED_TREE (t)); break; case INTEGER_CST: if (TREE_INT_CST_HIGH (t)) dump_int (di, "high", TREE_INT_CST_HIGH (t)); dump_int (di, "low", TREE_INT_CST_LOW (t)); break; case STRING_CST: fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t)); dump_int (di, "lngt", TREE_STRING_LENGTH (t)); break; case REAL_CST: dump_real (di, "valu", TREE_REAL_CST_PTR (t)); break; case FIXED_CST: dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t)); break; case TRUTH_NOT_EXPR: case ADDR_EXPR: case INDIRECT_REF: case CLEANUP_POINT_EXPR: case SAVE_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: /* These nodes are unary, but do not have code class `1'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case INIT_EXPR: case MODIFY_EXPR: case COMPOUND_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: /* These nodes are binary, but do not have code class `2'. */ dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case COMPONENT_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case ARRAY_REF: case ARRAY_RANGE_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); dump_child ("op 3", TREE_OPERAND (t, 3)); break; case COND_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); break; case TRY_FINALLY_EXPR: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); break; case CALL_EXPR: { int i = 0; tree arg; call_expr_arg_iterator iter; dump_child ("fn", CALL_EXPR_FN (t)); FOR_EACH_CALL_EXPR_ARG (arg, iter, t) { char buffer[32]; sprintf (buffer, "%u", i); dump_child (buffer, arg); i++; } } break; case CONSTRUCTOR: { unsigned HOST_WIDE_INT cnt; tree index, value; dump_int (di, "lngt", VEC_length (constructor_elt, CONSTRUCTOR_ELTS (t))); FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value) { dump_child ("idx", index); dump_child ("val", value); } }
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; }