diff options
author | Jakub Jelinek <jakub@redhat.com> | 2017-11-19 18:17:01 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-11-19 18:17:01 +0100 |
commit | f9c59f7e9511856bd6dc13d2d4904ebd9249c095 (patch) | |
tree | 418d66f5607f88d0a122bfdd9c9fe4038f93d9f8 /gcc/c/c-fold.c | |
parent | 4397fc04e399e91fe53f0862fef41bb5b42a7c14 (diff) | |
download | gcc-f9c59f7e9511856bd6dc13d2d4904ebd9249c095.zip gcc-f9c59f7e9511856bd6dc13d2d4904ebd9249c095.tar.gz gcc-f9c59f7e9511856bd6dc13d2d4904ebd9249c095.tar.bz2 |
re PR c/66618 (Failure to diagnose non-constant initializer for static object with -O1)
PR c/66618
PR c/69960
c-family/
* c-common.h (c_fully_fold): Add LVAL argument defaulted to false.
c/
* c-parser.c (c_parser_omp_atomic): Pass true as LVAL to c_fully_fold
where needed.
* c-typeck.c (build_unary_op, build_modify_expr, build_asm_expr,
handle_omp_array_sections): Likewise.
(digest_init): Don't call decl_constant_value_for_optimization.
* c-tree.h (decl_constant_value_for_optimization): Removed.
* c-fold.c (c_fold_array_ref): New function.
(c_fully_fold_internal): Add LVAL argument, propagate it through
recursive calls. For VAR_P call decl_constant_value and
unshare if not LVAL and either optimizing or IN_INIT. Remove
decl_constant_value_for_optimization calls. If IN_INIT and not LVAL,
fold ARRAY_REF with STRING_CST and INTEGER_CST operands.
(c_fully_fold): Add LVAL argument, pass it through to
c_fully_fold_internal.
(decl_constant_value_for_optimization): Removed.
cp/
* cp-gimplify.c (c_fully_fold): Add LVAL argument, call
cp_fold_maybe_rvalue instead of cp_fold_rvalue and pass it !LVAL.
testsuite/
* gcc.dg/pr69960.c: New test.
* gcc.dg/pr66618.c: New test.
* gcc.dg/pr66618-2.c: New test.
From-SVN: r254930
Diffstat (limited to 'gcc/c/c-fold.c')
-rw-r--r-- | gcc/c/c-fold.c | 165 |
1 files changed, 100 insertions, 65 deletions
diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c index 0abc4ac..6a6c716 100644 --- a/gcc/c/c-fold.c +++ b/gcc/c/c-fold.c @@ -27,7 +27,8 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "gimplify.h" -static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool); +static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool, + bool); /* If DISABLE is true, stop issuing warnings. This is used when parsing code that we know will not be executed. This function may @@ -55,6 +56,40 @@ c_enable_warnings (bool enable) } } +/* Try to fold ARRAY_REF ary[index] if possible and not handled by + normal fold, return NULL_TREE otherwise. */ + +static tree +c_fold_array_ref (tree type, tree ary, tree index) +{ + if (TREE_CODE (ary) != STRING_CST + || TREE_CODE (index) != INTEGER_CST + || TREE_OVERFLOW (index) + || TREE_CODE (TREE_TYPE (ary)) != ARRAY_TYPE + || !tree_fits_uhwi_p (index)) + return NULL_TREE; + + tree elem_type = TREE_TYPE (TREE_TYPE (ary)); + unsigned elem_nchars = (TYPE_PRECISION (elem_type) + / TYPE_PRECISION (char_type_node)); + unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; + tree nelts = array_type_nelts (TREE_TYPE (ary)); + bool dummy1 = true, dummy2 = true; + nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false); + unsigned HOST_WIDE_INT i = tree_to_uhwi (index); + if (!tree_int_cst_le (index, nelts) + || i >= len + || i + elem_nchars > len) + return NULL_TREE; + + if (elem_nchars == 1) + return build_int_cst (type, TREE_STRING_POINTER (ary)[i]); + + const unsigned char *ptr + = ((const unsigned char *)TREE_STRING_POINTER (ary) + i * elem_nchars); + return native_interpret_expr (type, ptr, elem_nchars); +} + /* Fully fold EXPR, an expression that was not folded (beyond integer constant expressions and null pointer constants) when being built up. If IN_INIT, this is in a static initializer and certain @@ -68,10 +103,11 @@ c_enable_warnings (bool enable) folded expression. Function arguments have already been folded before calling this function, as have the contents of SAVE_EXPR, TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and - C_MAYBE_CONST_EXPR. */ + C_MAYBE_CONST_EXPR. LVAL is true if it should be treated as an + lvalue. */ tree -c_fully_fold (tree expr, bool in_init, bool *maybe_const) +c_fully_fold (tree expr, bool in_init, bool *maybe_const, bool lval) { tree ret; tree eptype = NULL_TREE; @@ -87,7 +123,7 @@ c_fully_fold (tree expr, bool in_init, bool *maybe_const) expr = TREE_OPERAND (expr, 0); } ret = c_fully_fold_internal (expr, in_init, maybe_const, - &maybe_const_itself, false); + &maybe_const_itself, false, lval); if (eptype) ret = fold_convert_loc (loc, eptype, ret); *maybe_const &= maybe_const_itself; @@ -102,11 +138,13 @@ c_fully_fold (tree expr, bool in_init, bool *maybe_const) *MAYBE_CONST_ITSELF is carried from only evaluated subexpressions). FOR_INT_CONST indicates if EXPR is an expression with integer constant operands, and if any of the operands doesn't - get folded to an integer constant, don't fold the expression itself. */ + get folded to an integer constant, don't fold the expression itself. + LVAL indicates folding of lvalue, where we can't replace it with + an rvalue. */ static tree c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, - bool *maybe_const_itself, bool for_int_const) + bool *maybe_const_itself, bool for_int_const, bool lval) { tree ret = expr; enum tree_code code = TREE_CODE (expr); @@ -118,14 +156,27 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, bool op0_const_self = true, op1_const_self = true, op2_const_self = true; bool nowarning = TREE_NO_WARNING (expr); bool unused_p; + bool op0_lval = false; source_range old_range; /* Constants, declarations, statements, errors, 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) - return expr; + if (!IS_EXPR_CODE_CLASS (kind) || kind == tcc_statement) + { + /* Except for variables which we can optimize to its initializer. */ + if (VAR_P (expr) && !lval && (optimize || in_init)) + { + ret = decl_constant_value (expr); + /* Avoid unwanted tree sharing between the initializer and current + function's body where the tree can be modified e.g. by the + gimplifier. */ + if (ret != expr && TREE_STATIC (expr)) + ret = unshare_expr (ret); + return ret; + } + return expr; + } if (IS_EXPR_CODE_CLASS (kind)) old_range = EXPR_LOCATION_RANGE (expr); @@ -150,7 +201,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, { *maybe_const_itself = false; inner = c_fully_fold_internal (inner, in_init, maybe_const_operands, - maybe_const_itself, true); + maybe_const_itself, true, lval); } if (pre && !in_init) ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner); @@ -201,7 +252,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + maybe_const_itself, for_int_const, lval); STRIP_TYPE_NOPS (op0); if (op0 != orig_op0) ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2); @@ -218,12 +269,19 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + maybe_const_itself, for_int_const, lval); STRIP_TYPE_NOPS (op0); op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself, for_int_const); + maybe_const_itself, for_int_const, false); STRIP_TYPE_NOPS (op1); - op1 = decl_constant_value_for_optimization (op1); + /* Fold "foo"[2] in initializers. */ + if (!lval && in_init) + { + ret = c_fold_array_ref (TREE_TYPE (expr), op0, op1); + if (ret) + goto out; + ret = expr; + } if (op0 != orig_op0 || op1 != orig_op1) ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3); if (ret != expr) @@ -232,15 +290,18 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); } - ret = fold (ret); + if (!lval) + ret = fold (ret); goto out; - case COMPOUND_EXPR: case MODIFY_EXPR: case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: + op0_lval = true; + /* FALLTHRU */ + case COMPOUND_EXPR: case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: @@ -278,21 +339,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + maybe_const_itself, for_int_const, + op0_lval); 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); + maybe_const_itself, for_int_const, false); 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)) @@ -370,6 +425,13 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, warn_for_div_by_zero (loc, op1); goto out; + case ADDR_EXPR: + op0_lval = true; + goto unary; + case REALPART_EXPR: + case IMAGPART_EXPR: + op0_lval = lval; + /* FALLTHRU */ case INDIRECT_REF: case FIX_TRUNC_EXPR: case FLOAT_EXPR: @@ -380,17 +442,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, case NEGATE_EXPR: case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: - case ADDR_EXPR: case CONJ_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: + unary: /* 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); + maybe_const_itself, for_int_const, + op0_lval); 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; @@ -440,7 +499,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + for_int_const, false); STRIP_TYPE_NOPS (op0); unused_p = (op0 == (code == TRUTH_ANDIF_EXPR @@ -448,7 +507,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, : truthvalue_true_node)); c_disable_warnings (unused_p); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self, - for_int_const); + for_int_const, false); STRIP_TYPE_NOPS (op1); c_enable_warnings (unused_p); @@ -486,18 +545,18 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + for_int_const, false); 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); + for_int_const, false); 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); + for_int_const, false); STRIP_TYPE_NOPS (op2); c_enable_warnings (op0 == truthvalue_true_node); @@ -540,13 +599,13 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, 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); + maybe_const_itself, for_int_const, false); STRIP_TYPE_NOPS (op0); op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, - maybe_const_itself, for_int_const); + maybe_const_itself, for_int_const, false); STRIP_TYPE_NOPS (op1); op2 = c_fully_fold_internal (op2, in_init, maybe_const_operands, - maybe_const_itself, for_int_const); + maybe_const_itself, for_int_const, false); STRIP_TYPE_NOPS (op2); if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) @@ -570,7 +629,8 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, if (!SAVE_EXPR_FOLDED_P (expr)) { op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, - maybe_const_itself, for_int_const); + maybe_const_itself, for_int_const, + false); TREE_OPERAND (expr, 0) = op0; SAVE_EXPR_FOLDED_P (expr) = true; } @@ -604,28 +664,3 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, } return ret; } - -/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type, - return EXP. Otherwise, return either EXP or its known constant - value (if it has one), but return EXP if EXP has mode BLKmode. ??? - Is the BLKmode test appropriate? */ - -tree -decl_constant_value_for_optimization (tree exp) -{ - tree ret; - - if (!optimize - || !VAR_P (exp) - || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE - || DECL_MODE (exp) == BLKmode) - return exp; - - ret = decl_constant_value (exp); - /* Avoid unwanted tree sharing between the initializer and current - function's body where the tree can be modified e.g. by the - gimplifier. */ - if (ret != exp && TREE_STATIC (exp)) - ret = unshare_expr (ret); - return ret; -} |