From f9c59f7e9511856bd6dc13d2d4904ebd9249c095 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 19 Nov 2017 18:17:01 +0100 Subject: [PATCH] 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 --- gcc/c-family/ChangeLog | 6 ++ gcc/c-family/c-common.h | 2 +- gcc/c/ChangeLog | 20 ++++ gcc/c/c-fold.c | 165 +++++++++++++++++++------------ gcc/c/c-parser.c | 30 +++--- gcc/c/c-tree.h | 2 - gcc/c/c-typeck.c | 11 +-- gcc/cp/ChangeLog | 7 ++ gcc/cp/cp-gimplify.c | 6 +- gcc/testsuite/ChangeLog | 8 ++ gcc/testsuite/gcc.dg/pr66618-2.c | 10 ++ gcc/testsuite/gcc.dg/pr66618.c | 11 +++ gcc/testsuite/gcc.dg/pr69960.c | 12 +++ 13 files changed, 199 insertions(+), 91 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr66618-2.c create mode 100644 gcc/testsuite/gcc.dg/pr66618.c create mode 100644 gcc/testsuite/gcc.dg/pr69960.c diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 990cd6163bc..7323a7d4c91 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2017-11-19 Jakub Jelinek + + PR c/66618 + PR c/69960 + * c-common.h (c_fully_fold): Add LVAL argument defaulted to false. + 2017-11-16 Joseph Myers * c.opt (-std=c17, std=gnu17, -std=iso9899:2017): Refer to 2018 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 5bb86191d2b..c86c6598c50 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -828,7 +828,7 @@ extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); extern enum conversion_safety unsafe_conversion_p (location_t, tree, tree, tree, bool); extern bool decl_with_nonnull_addr_p (const_tree); -extern tree c_fully_fold (tree, bool, bool *); +extern tree c_fully_fold (tree, bool, bool *, bool = false); extern tree c_wrap_maybe_const (tree, bool); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 5622c8ae787..b10ebfc793a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,23 @@ +2017-11-19 Jakub Jelinek + + PR c/66618 + PR c/69960 + * 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. + 2017-11-15 Joseph Myers PR c/81156 diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c index 0abc4acc37f..6a6c7163bbe 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; -} diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 3d90e28caad..bd5dd5799a0 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -15312,7 +15312,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) case NOP_EXPR: /* atomic write */ v = c_parser_cast_expression (parser, NULL).value; non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL); + v = c_fully_fold (v, false, NULL, true); if (v == error_mark_node) goto saw_error; if (non_lvalue_p) @@ -15331,7 +15331,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { lhs = c_parser_cast_expression (parser, NULL).value; non_lvalue_p = !lvalue_p (lhs); - lhs = c_fully_fold (lhs, false, NULL); + lhs = c_fully_fold (lhs, false, NULL, true); if (lhs == error_mark_node) goto saw_error; if (non_lvalue_p) @@ -15357,7 +15357,7 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) { v = c_parser_cast_expression (parser, NULL).value; non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL); + v = c_fully_fold (v, false, NULL, true); if (v == error_mark_node) goto saw_error; if (non_lvalue_p) @@ -15378,7 +15378,7 @@ restart: lhs = expr.value; expr = default_function_array_conversion (eloc, expr); unfolded_lhs = expr.value; - lhs = c_fully_fold (lhs, false, NULL); + lhs = c_fully_fold (lhs, false, NULL, true); orig_lhs = lhs; switch (TREE_CODE (lhs)) { @@ -15518,15 +15518,19 @@ restart: if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs)) { opcode = TREE_CODE (rhs1); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); - rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, + true); goto stmt_done; } if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs)) { opcode = TREE_CODE (rhs1); - rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL); - rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL); + rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL, + true); + rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL, + true); swapped = !commutative_tree_code (opcode); goto stmt_done; } @@ -15545,7 +15549,7 @@ restart: lhs = NULL_TREE; expr = default_function_array_read_conversion (eloc, expr); unfolded_lhs1 = expr.value; - lhs1 = c_fully_fold (unfolded_lhs1, false, NULL); + lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true); rhs1 = NULL_TREE; c_parser_consume_token (parser); goto restart; @@ -15554,7 +15558,7 @@ restart: { opcode = NOP_EXPR; expr = default_function_array_read_conversion (eloc, expr); - rhs = c_fully_fold (expr.value, false, NULL); + rhs = c_fully_fold (expr.value, false, NULL, true); rhs1 = NULL_TREE; goto stmt_done; } @@ -15575,7 +15579,7 @@ restart: expr = c_parser_expression (parser); expr = default_function_array_read_conversion (eloc, expr); rhs = expr.value; - rhs = c_fully_fold (rhs, false, NULL); + rhs = c_fully_fold (rhs, false, NULL, true); break; } stmt_done: @@ -15585,7 +15589,7 @@ stmt_done: goto saw_error; v = c_parser_cast_expression (parser, NULL).value; non_lvalue_p = !lvalue_p (v); - v = c_fully_fold (v, false, NULL); + v = c_fully_fold (v, false, NULL, true); if (v == error_mark_node) goto saw_error; if (non_lvalue_p) @@ -15597,7 +15601,7 @@ stmt_done: lhs1 = expr.value; expr = default_function_array_read_conversion (eloc, expr); unfolded_lhs1 = expr.value; - lhs1 = c_fully_fold (lhs1, false, NULL); + lhs1 = c_fully_fold (lhs1, false, NULL, true); if (lhs1 == error_mark_node) goto saw_error; if (!lvalue_p (unfolded_lhs1)) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 11356476d84..5fb57f21bd1 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -770,8 +770,6 @@ set_c_expr_source_range (c_expr *expr, source_range src_range); /* In c-fold.c */ -extern tree decl_constant_value_for_optimization (tree); - extern vec incomplete_record_decls; #if CHECKING_P diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4bdc48a9ea3..8a09ea2ea46 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4398,7 +4398,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, } /* Ensure the argument is fully folded inside any SAVE_EXPR. */ - arg = c_fully_fold (arg, false, NULL); + arg = c_fully_fold (arg, false, NULL, true); bool atomic_op; atomic_op = really_atomic_lvalue (arg); @@ -5822,7 +5822,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, if (modifycode != NOP_EXPR) { - lhs = c_fully_fold (lhs, false, NULL); + lhs = c_fully_fold (lhs, false, NULL, true); lhs = stabilize_reference (lhs); /* Construct the RHS for any non-atomic compound assignemnt. */ @@ -7289,7 +7289,6 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, inside_init = TREE_OPERAND (inside_init, 0); } inside_init = c_fully_fold (inside_init, require_constant, &maybe_const); - inside_init = decl_constant_value_for_optimization (inside_init); /* Initialization of an array of chars from a string constant optionally enclosed in braces. */ @@ -9899,7 +9898,7 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, { tree output = TREE_VALUE (tail); - output = c_fully_fold (output, false, NULL); + output = c_fully_fold (output, false, NULL, true); /* ??? Really, this should not be here. Users should be using a proper lvalue, dammit. But there's a long history of using casts @@ -9957,7 +9956,7 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, mark it addressable. */ if (!allows_reg && allows_mem) { - input = c_fully_fold (input, false, NULL); + input = c_fully_fold (input, false, NULL, true); /* Strip the nops as we allow this case. FIXME, this really should be rejected or made deprecated. */ @@ -12723,7 +12722,7 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) } if (tem) first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); - first = c_fully_fold (first, false, NULL); + first = c_fully_fold (first, false, NULL, true); OMP_CLAUSE_DECL (c) = first; } else diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e0bb1b1ddd4..410b18b42fd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-11-19 Jakub Jelinek + + PR c/66618 + PR c/69960 + * cp-gimplify.c (c_fully_fold): Add LVAL argument, call + cp_fold_maybe_rvalue instead of cp_fold_rvalue and pass it !LVAL. + 2017-11-16 Jason Merrill PR c++/79092 - non-type args of different types are different diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 7c7c0409af8..8849f9d3735 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2048,11 +2048,9 @@ cp_fully_fold (tree x) C_MAYBE_CONST_EXPR. */ tree -c_fully_fold (tree x, bool /*in_init*/, bool */*maybe_const*/) +c_fully_fold (tree x, bool /*in_init*/, bool */*maybe_const*/, bool lval) { - /* c_fully_fold is only used on rvalues, and we need to fold CONST_DECL to - INTEGER_CST. */ - return cp_fold_rvalue (x); + return cp_fold_maybe_rvalue (x, !lval); } static GTY((deletable)) hash_map *fold_cache; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 25cb660fb38..705730b5706 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2017-11-19 Jakub Jelinek + + PR c/66618 + PR c/69960 + * gcc.dg/pr69960.c: New test. + * gcc.dg/pr66618.c: New test. + * gcc.dg/pr66618-2.c: New test. + 2017-11-18 Janne Blomqvist PR fortran/44292 diff --git a/gcc/testsuite/gcc.dg/pr66618-2.c b/gcc/testsuite/gcc.dg/pr66618-2.c new file mode 100644 index 00000000000..3cb2e44c378 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr66618-2.c @@ -0,0 +1,10 @@ +/* PR c/66618 */ +/* { dg-do compile } */ +/* { dg-options "-pedantic-errors" } */ + +int a = "foo"[2]; +int b = 1["bar"]; +int c = "baz"[__INT_MAX__ * -2]; /* { dg-error "initializer element is not constant" } */ +int d = "str"[3]; /* { dg-warning "integer overflow in expression of type" "" { target *-*-* } .-1 } */ +int e = "str"[4]; /* { dg-error "initializer element is not constant" } */ +int f = "str"[-1]; /* { dg-error "initializer element is not constant" } */ diff --git a/gcc/testsuite/gcc.dg/pr66618.c b/gcc/testsuite/gcc.dg/pr66618.c new file mode 100644 index 00000000000..649d4f652df --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr66618.c @@ -0,0 +1,11 @@ +/* PR c/66618 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +int +foo (void) +{ + const int a = 0; + static int b = a; /* { dg-bogus "initializer element is not constant" } */ + return b; +} diff --git a/gcc/testsuite/gcc.dg/pr69960.c b/gcc/testsuite/gcc.dg/pr69960.c new file mode 100644 index 00000000000..e339d30b435 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr69960.c @@ -0,0 +1,12 @@ +/* PR c/69960 */ +/* { dg-do compile { target int32plus } } */ + +#define TOLOWER(x) (x&~0x20) +#define Word(s) \ + s[1] ? s[2] ? s[3] ? \ + (TOLOWER(s[0]) << 24) + (TOLOWER(s[1]) << 16) + (TOLOWER(s[2]) << 8) + TOLOWER(s[3]) : \ + (TOLOWER(s[0]) << 16) + (TOLOWER(s[1]) << 8) + TOLOWER(s[2]) : \ + (TOLOWER(s[0]) << 8) + TOLOWER(s[1]) : \ + TOLOWER(s[0]) + +const unsigned int _the = Word("the"); -- 2.30.2