diff options
author | Joseph Myers <joseph@codesourcery.com> | 2009-03-29 19:13:43 +0100 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2009-03-29 19:13:43 +0100 |
commit | 928c19bbb001967c7ab83a9f856c740680b6661f (patch) | |
tree | a06c7550ad4d8d100141b10b1c0d61bf7548b888 /gcc/c-common.c | |
parent | 5babbcc0fceb0aa66547feb61124ff548929cbfc (diff) | |
download | gcc-928c19bbb001967c7ab83a9f856c740680b6661f.zip gcc-928c19bbb001967c7ab83a9f856c740680b6661f.tar.gz gcc-928c19bbb001967c7ab83a9f856c740680b6661f.tar.bz2 |
re PR c/456 (constant expressions constraints (gcc.dg/c90-const-expr-1))
PR c/456
PR c/5675
PR c/19976
PR c/29116
PR c/31871
PR c/35198
fixincludes:
* inclhack.def (glibc_tgmath): New fix.
* fixincl.x: Regenerate.
* tests/base/tgmath.h: New.
gcc:
* builtins.c (fold_builtin_sincos): Build COMPOUND_EXPR in
void_type_node.
(fold_call_expr): Return a NOP_EXPR from folding rather than the
contained expression.
* c-common.c (c_fully_fold, c_fully_fold_internal, c_save_expr):
New.
(c_common_truthvalue_conversion): Use c_save_expr. Do not fold
conditional expressions for C.
(decl_constant_value_for_optimization): Move from
decl_constant_value_for_broken_optimization in c-typeck.c. Check
whether optimizing and that the expression is a VAR_DECL not of
array type instead of doing such checks in the caller. Do not
check pedantic. Call gcc_unreachable for C++.
* c-common.def (C_MAYBE_CONST_EXPR): New.
* c-common.h (c_fully_fold, c_save_expr,
decl_constant_value_for_optimization): New prototypes.
(C_MAYBE_CONST_EXPR_PRE, C_MAYBE_CONST_EXPR_EXPR,
C_MAYBE_CONST_EXPR_INT_OPERANDS, C_MAYBE_CONST_EXPR_NON_CONST,
EXPR_INT_CONST_OPERANDS): Define.
* c-convert.c (convert): Strip nops from expression.
* c-decl.c (groktypename): Take extra parameters expr and
expr_const_operands. Update call to grokdeclarator.
(start_decl): Update call to grokdeclarator. Add statement for
expressions used in type of decl.
(grokparm): Update call to grokdeclarator.
(push_parm_decl): Update call to grokdeclarator.
(build_compound_literal): Add parameter non_const and build a
C_MAYBE_COSNT_EXPR if applicable.
(grokdeclarator): Take extra parameters expr and
expr_const_operands. Track expressions used in declaration
specifiers and declarators. Fold array sizes and track whether
they are constant expressions and whether they are integer
constant expressions.
(parser_xref_tag): Set expr and expr_const_operands fields in
return value.
(grokfield): Update call to grokdeclarator.
(start_function): Update call to grokdeclarator.
(build_null_declspecs): Set expr and expr_const_operands fields in
return value.
(declspecs_add_type): Handle expressions in typeof specifiers.
* c-parser.c (c_parser_declspecs): Set expr and
expr_const_operands fields for declaration specifiers.
(c_parser_enum_specifier): Likewise.
(c_parser_struct_or_union_specifier): Likewise.
(c_parser_typeof_specifier): Likewise. Update call to
groktypename. Fold expression as needed. Return expressions with
type instead of adding statements.
(c_parser_attributes): Update calls to c_parser_expr_list.
(c_parser_statement_after_labels): Fold expression before passing
to objc_build_throw_stmt.
(c_parser_condition): Fold expression.
(c_parser_asm_operands): Fold expression.
(c_parser_conditional_expression): Use c_save_expr. Update call
to build_conditional_expr.
(c_parser_alignof_expression): Update call to groktypename.
(c_parser_postfix_expression): Preserve C_MAYBE_CONST_EXPR as
original_code. Fold expression argument of va_arg. Create
C_MAYBE_CONST_EXPR to preserve side effects of expressions in type
argument to va_arg. Update calls to groktypename. Fold array
index for offsetof. Verify that first argument to
__builtin_choose_expr has integer type.
(c_parser_postfix_expression_after_paren_type): Update calls to
groktypename and build_compound_literal. Handle expressions with
side effects in type name.
(c_parser_postfix_expression_after_primary): Update call to
c_parser_expr_list. Set original_code for calls to
__builtin_constant_p.
(c_parser_expr_list): Take extra parameter fold_p. Fold
expressions if requested.
(c_parser_objc_type_name): Update call to groktypename.
(c_parser_objc_synchronized_statement): Fold expression.
(c_parser_objc_receiver): Fold expression.
(c_parser_objc_keywordexpr): Update call to c_parser_expr_list.
(c_parser_omp_clause_num_threads, c_parser_omp_clause_schedule,
c_parser_omp_atomic, c_parser_omp_for_loop): Fold expressions.
* c-tree.h (CONSTRUCTOR_NON_CONST): Define.
(struct c_typespec): Add elements expr and expr_const_operands.
(struct c_declspecs): Add elements expr and expr_const_operands.
(groktypename, build_conditional_expr, build_compound_literal):
Update prototypes.
(in_late_binary_op): Declare.
* c-typeck.c (note_integer_operands): New function.
(in_late_binary_op): New variable.
(decl_constant_value_for_broken_optimization): Move to c-common.c
and rename to decl_constant_value_for_optimization.
(default_function_array_conversion): Do not strip nops.
(default_conversion): Do not call
decl_constant_value_for_broken_optimization.
(build_array_ref): Do not fold result.
(c_expr_sizeof_expr): Fold operand. Use C_MAYBE_CONST_EXPR for
result when operand is a VLA.
(c_expr_sizeof_type): Update call to groktypename. Handle
expressions included in type name. Use C_MAYBE_CONST_EXPR for
result when operand names a VLA type.
(build_function_call): Update call to build_compound_literal.
Only fold result for calls to __builtin_* functions. Strip
NOP_EXPR from INTEGER_CST returned from such functions. Fold
the function designator.
(convert_arguments): Fold arguments. Update call to
convert_for_assignment.
(build_unary_op): Handle increment and decrement of
C_MAYBE_CONST_EXPR. Move lvalue checks for increment and
decrement earlier. Fold operand of increment and decrement.
Handle address of C_MAYBE_CONST_EXPR. Only fold expression being
built for integer operand. Wrap returns that are INTEGER_CSTs
without being integer constant expressions or that have integer
constant operands without being INTEGER_CSTs.
(lvalue_p): Handle C_MAYBE_CONST_EXPR.
(build_conditional_expr): Add operand ifexp_bcp. Track whether
result is an integer constant expression or can be used in
unevaluated parts of one and avoid folding and wrap as
appropriate. Fold operands before possibly doing -Wsign-compare
warnings.
(build_compound_expr): Wrap result for C99 if operands can be used
in integer constant expressions.
(build_c_cast): Update call to digest_init. Do not ignore
overflow from casting floating-point constants to integers. Wrap
results that could be confused with integer constant expressions,
null pointer constants or floating-point constants.
(c_cast_expr): Update call to groktypename. Handle expressions
included in type name.
(build_modify_expr): Handle modifying a C_MAYBE_CONST_EXPR. Fold
lhs inside possible SAVE_EXPR. Fold RHS before assignment.
Update calls to convert_for_assignment.
(convert_for_assignment): Take new parameter
null_pointer_constant. Do not strip nops or call
decl_constant_value_for_broken_optimization. Set
in_late_binary_op for conversions to boolean.
(store_init_value): Update call to digest_init.
(digest_init): Take new parameter null_pointer_constant. Do not
call decl_constant_value_for_broken_optimization. pedwarn for
initializers not constant expressions. Update calls to
convert_for_assignment.
(constructor_nonconst): New.
(struct constructor_stack): Add nonconst element.
(really_start_incremental_init, push_init_level, pop_init_level):
Handle constructor_nonconst and nonconst element.
(set_init_index): Call constant_expression_warning for array
designators.
(output_init_element): Fold value. Set constructor_nonconst as
applicable. pedwarn for initializers not constant expressions.
Update call to digest_init. Call constant_expression_warning
where constant initializers are required.
(process_init_element): Use c_save_expr.
(c_finish_goto_ptr): Fold expression.
(c_finish_return): Fold return value. Update call to
convert_for_assignment.
(c_start_case): Fold switch expression.
(c_process_expr_stmt): Fold expression.
(c_finish_stmt_expr): Create C_MAYBE_CONST_EXPR as needed to
ensure statement expression is not evaluated in constant
expression.
(build_binary_op): Track whether results are integer constant
expressions or may occur in such, disable folding and wrap results
as applicable. Fold operands for -Wsign-compare warnings unless
in_late_binary_op.
(c_objc_common_truthvalue_conversion): Handle results folded to
integer constants that are not integer constant expressions.
* doc/extend.texi: Document when typeof operands are evaluated,
that condition of __builtin_choose_expr is an integer constant
expression, and more about use of __builtin_constant_p in
initializers.
gcc/objc:
* objc-act.c (objc_finish_try_stmt): Set in_late_binary_op.
gcc/testsuite:
* gcc.c-torture/compile/20081108-1.c,
gcc.c-torture/compile/20081108-2.c,
gcc.c-torture/compile/20081108-3.c, gcc.dg/bconstp-2.c,
gcc.dg/bconstp-3.c, gcc.dg/bconstp-4.c, gcc.dg/c90-const-expr-6.c,
gcc.dg/c90-const-expr-7.c, gcc.dg/c90-const-expr-8.c,
gcc.dg/c90-const-expr-9.c, gcc.dg/c90-const-expr-10.c,
gcc.dg/c90-const-expr-11.c, gcc.dg/c99-const-expr-6.c,
gcc.dg/c99-const-expr-7.c, gcc.dg/c99-const-expr-8.c,
gcc.dg/c99-const-expr-9.c, gcc.dg/c99-const-expr-10.c,
gcc.dg/c99-const-expr-11.c, gcc.dg/c99-const-expr-12.c,
gcc.dg/c99-const-expr-13.c, gcc.dg/compare10.c,
gcc.dg/gnu89-const-expr-1.c, gcc.dg/gnu89-const-expr-2.c,
gcc.dg/gnu99-const-expr-1.c, gcc.dg/gnu99-const-expr-2.c,
gcc.dg/gnu99-const-expr-3.c, gcc.dg/vla-12.c, gcc.dg/vla-13.c,
gcc.dg/vla-14.c, gcc.dg/vla-15.c, gcc.dg/vla-16.c: New tests.
* gcc.dg/c90-const-expr-1.c, gcc.dg/c90-const-expr-2.c,
gcc.dg/c90-const-expr-3.c, gcc.dg/c99-const-expr-2.c,
gcc.dg/c99-const-expr-3.c, gcc.dg/c99-static-1.c: Remove XFAILs.
* gcc.dg/c90-const-expr-2.c: Use ZERO in place of 0 in another
case.
* gcc.dg/overflow-warn-1.c, gcc.dg/overflow-warn-2.c,
gcc.dg/overflow-warn-3.c, gcc.dg/overflow-warn-4.c: Remove
XFAILs. Update expected messages.
* gcc.dg/pr14649-1.c, gcc.dg/pr19984.c, gcc.dg/pr25682.c: Update
expected messages.
* gcc.dg/real-const-1.c: Replace with test from original PR.
* gcc.dg/vect/pr32230.c: Use intermediate cast to __PTRDIFF_TYPE__
when casting from non-constant integer to pointer.
From-SVN: r145254
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 431 |
1 files changed, 424 insertions, 7 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 9b066f4..c066e95 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -518,6 +518,7 @@ const struct fname_var_t fname_vars[] = {NULL, 0, 0}, }; +static tree c_fully_fold_internal (tree expr, bool, bool *, bool *); static tree check_case_value (tree); static bool check_case_bounds (tree, tree, tree *, tree *); @@ -1107,6 +1108,390 @@ fix_string_type (tree value) return value; } +/* 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 + changes are made to the folding done. Clear *MAYBE_CONST if + MAYBE_CONST is not NULL and EXPR is definitely not a constant + expression because it contains an evaluated operator (in C99) or an + operator outside of sizeof returning an integer constant (in C90) + not permitted in constant expressions, or because it contains an + evaluated arithmetic overflow. (*MAYBE_CONST should typically be + set to true by callers before calling this function.) Return the + 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. */ + +tree +c_fully_fold (tree expr, bool in_init, bool *maybe_const) +{ + tree ret; + bool dummy = true; + bool maybe_const_itself = true; + + /* This function is not relevant to C++ because C++ folds while + parsing, and may need changes to be correct for C++ when C++ + stops folding while parsing. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + if (!maybe_const) + maybe_const = &dummy; + ret = c_fully_fold_internal (expr, in_init, maybe_const, + &maybe_const_itself); + *maybe_const &= maybe_const_itself; + return ret; +} + +/* Internal helper for c_fully_fold. EXPR and IN_INIT are as for + c_fully_fold. *MAYBE_CONST_OPERANDS is cleared because of operands + not permitted, while *MAYBE_CONST_ITSELF is cleared because of + arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from + both evaluated and unevaluated subexpressions while + *MAYBE_CONST_ITSELF is carried from only evaluated + subexpressions). */ + +static tree +c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, + bool *maybe_const_itself) +{ + 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); + + /* This function is not relevant to C++ because C++ folds while + parsing, and may need changes to be correct for C++ when C++ + stops folding while parsing. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + /* 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; + + /* 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; + 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); + 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); + op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, + maybe_const_itself); + 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); + 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); + op1 = decl_constant_value_for_optimization (op1); + if (op0 != orig_op0 || op1 != orig_op1 || in_init) + ret = in_init + ? fold_build2_initializer (code, TREE_TYPE (expr), op0, op1) + : fold_build2 (code, TREE_TYPE (expr), op0, op1); + else + ret = fold (expr); + goto out; + + case INDIRECT_REF: + case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + CASE_CONVERT: + 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); + if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR) + op0 = decl_constant_value_for_optimization (op0); + if (op0 != orig_op0 || in_init) + ret = in_init + ? fold_build1_initializer (code, TREE_TYPE (expr), op0) + : fold_build1 (code, TREE_TYPE (expr), op0); + else + ret = fold (expr); + if (code == INDIRECT_REF + && ret != expr + && TREE_CODE (ret) == INDIRECT_REF) + { + TREE_READONLY (ret) = TREE_READONLY (expr); + TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); + TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); + } + 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); + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + if (op0 != orig_op0 || op1 != orig_op1 || in_init) + ret = in_init + ? fold_build2_initializer (code, TREE_TYPE (expr), op0, op1) + : fold_build2 (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); + op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self); + if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) + ret = fold_build3 (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; + + 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); + 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; + + /* This function is only used by C, for c_fully_fold and other + optimization, and may not be correct for C++. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + if (!optimize + || TREE_CODE (exp) != VAR_DECL + || 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; +} + /* Print a warning if a constant expression had overflow in folding. Invoke this function on every expression that the language requires to be a constant expression. @@ -3328,6 +3713,27 @@ pointer_int_sum (location_t location, enum tree_code resultcode, return ret; } +/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but + for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR + around the SAVE_EXPR if needed so that c_fully_fold does not need + to look inside SAVE_EXPRs. */ + +tree +c_save_expr (tree expr) +{ + bool maybe_const = true; + if (c_dialect_cxx ()) + return save_expr (expr); + expr = c_fully_fold (expr, false, &maybe_const); + expr = save_expr (expr); + if (!maybe_const) + { + expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr); + C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1; + } + return expr; +} + /* Return whether EXPR is a declaration whose address can never be NULL. */ @@ -3470,12 +3876,23 @@ c_common_truthvalue_conversion (location_t location, tree expr) case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ - return fold_build3 (COND_EXPR, truthvalue_type_node, - TREE_OPERAND (expr, 0), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 1)), - c_common_truthvalue_conversion (location, - TREE_OPERAND (expr, 2))); + if (c_dialect_cxx ()) + return fold_build3 (COND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 0), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, + 1)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, + 2))); + else + /* Folding will happen later for C. */ + return build3 (COND_EXPR, truthvalue_type_node, + TREE_OPERAND (expr, 0), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 1)), + c_common_truthvalue_conversion (location, + TREE_OPERAND (expr, 2))); CASE_CONVERT: /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, @@ -3506,7 +3923,7 @@ c_common_truthvalue_conversion (location_t location, tree expr) if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) { - tree t = save_expr (expr); + tree t = c_save_expr (expr); return (build_binary_op (EXPR_LOCATION (expr), (TREE_SIDE_EFFECTS (expr) |