summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2009-03-29 18:13:43 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2009-03-29 18:13:43 +0000
commita75b1c712f1eaddc69919461ead67f4ac21663fe (patch)
treea06c7550ad4d8d100141b10b1c0d61bf7548b888 /gcc
parent088cc5d52e3bab879a7b3aa48b3de9127e948bb0 (diff)
downloadgcc-a75b1c712f1eaddc69919461ead67f4ac21663fe.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@145254 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog171
-rw-r--r--gcc/builtins.c3
-rw-r--r--gcc/c-common.c431
-rw-r--r--gcc/c-common.def17
-rw-r--r--gcc/c-common.h22
-rw-r--r--gcc/c-convert.c6
-rw-r--r--gcc/c-decl.c115
-rw-r--r--gcc/c-parser.c149
-rw-r--r--gcc/c-tree.h33
-rw-r--r--gcc/c-typeck.c644
-rw-r--r--gcc/doc/extend.texi15
-rw-r--r--gcc/objc/ChangeLog10
-rw-r--r--gcc/objc/objc-act.c7
-rw-r--r--gcc/testsuite/ChangeLog37
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20081108-1.c11
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20081108-2.c4
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20081108-3.c4
-rw-r--r--gcc/testsuite/gcc.dg/bconstp-2.c27
-rw-r--r--gcc/testsuite/gcc.dg/bconstp-3.c27
-rw-r--r--gcc/testsuite/gcc.dg/bconstp-4.c10
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-1.c10
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-10.c28
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-11.c27
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-2.c8
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-3.c14
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-6.c53
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-7.c35
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-8.c27
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-9.c26
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-10.c28
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-11.c46
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-12.c23
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-13.c15
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-2.c6
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-3.c14
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-6.c62
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-7.c43
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-8.c27
-rw-r--r--gcc/testsuite/gcc.dg/c99-const-expr-9.c26
-rw-r--r--gcc/testsuite/gcc.dg/c99-static-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/compare10.c16
-rw-r--r--gcc/testsuite/gcc.dg/gnu89-const-expr-1.c47
-rw-r--r--gcc/testsuite/gcc.dg/gnu89-const-expr-2.c23
-rw-r--r--gcc/testsuite/gcc.dg/gnu99-const-expr-1.c47
-rw-r--r--gcc/testsuite/gcc.dg/gnu99-const-expr-2.c23
-rw-r--r--gcc/testsuite/gcc.dg/gnu99-const-expr-3.c32
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-1.c9
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-2.c31
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-3.c17
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-4.c17
-rw-r--r--gcc/testsuite/gcc.dg/pr14649-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr19984.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr25682.c8
-rw-r--r--gcc/testsuite/gcc.dg/real-const-1.c3
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr32230.c2
-rw-r--r--gcc/testsuite/gcc.dg/vla-12.c50
-rw-r--r--gcc/testsuite/gcc.dg/vla-13.c99
-rw-r--r--gcc/testsuite/gcc.dg/vla-14.c33
-rw-r--r--gcc/testsuite/gcc.dg/vla-15.c27
-rw-r--r--gcc/testsuite/gcc.dg/vla-16.c70
60 files changed, 2537 insertions, 284 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4766e21c994..f31b531a781 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,174 @@
+2009-03-29 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/456
+ PR c/5675
+ PR c/19976
+ PR c/29116
+ PR c/31871
+ PR c/35198
+ * 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.
+
2009-03-29 Richard Guenther <rguenther@suse.de>
* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Properly
diff --git a/gcc/builtins.c b/gcc/builtins.c
index fab8a4c879d..e22c5f58964 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -7930,7 +7930,7 @@ fold_builtin_sincos (tree arg0, tree arg1, tree arg2)
call = build_call_expr (fn, 1, arg0);
call = builtin_save_expr (call);
- return build2 (COMPOUND_EXPR, type,
+ return build2 (COMPOUND_EXPR, void_type_node,
build2 (MODIFY_EXPR, void_type_node,
build_fold_indirect_ref (arg1),
build1 (IMAGPART_EXPR, type, call)),
@@ -10929,7 +10929,6 @@ fold_call_expr (tree exp, bool ignore)
if (CAN_HAVE_LOCATION_P (realret)
&& !EXPR_HAS_LOCATION (realret))
SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
- return realret;
}
return ret;
}
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 9b066f413c6..c066e956959 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)
diff --git a/gcc/c-common.def b/gcc/c-common.def
index 54ebfc4f3df..3080fd3cee8 100644
--- a/gcc/c-common.def
+++ b/gcc/c-common.def
@@ -2,7 +2,7 @@
additional tree codes used in the GNU C compiler (see tree.def
for the standard codes).
Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998,
- 1999, 2000, 2001, 2004, 2005, 2007 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
Written by Benjamin Chelf <chelf@codesourcery.com>
This file is part of GCC.
@@ -31,6 +31,21 @@ along with GCC; see the file COPYING3. If not see
the compound literal. */
DEFTREECODE (COMPOUND_LITERAL_EXPR, "compound_literal_expr", tcc_expression, 1)
+/* A C_MAYBE_CONST_EXPR, currently only used for C and Objective C,
+ tracks information about constancy of an expression and VLA type
+ sizes or VM expressions from typeof that need to be evaluated
+ before the main expression. It is used during parsing and removed
+ in c_fully_fold. C_MAYBE_CONST_EXPR_PRE is the expression to
+ evaluate first, if not NULL; C_MAYBE_CONST_EXPR_EXPR is the main
+ expression. If C_MAYBE_CONST_EXPR_INT_OPERANDS is set then the
+ expression may be used in an unevaluated part of an integer
+ constant expression, but not in an evaluated part. If
+ C_MAYBE_CONST_EXPR_NON_CONST is set then the expression contains
+ something that cannot occur in an evaluated part of a constant
+ expression (or outside of sizeof in C90 mode); otherwise it does
+ not. */
+DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2)
+
/*
Local variables:
mode:c
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 6ba33c6aedc..ce8b23826ce 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -1,6 +1,6 @@
/* Definitions for c-common.c.
Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
@@ -30,8 +30,10 @@ along with GCC; see the file COPYING3. If not see
0: TREE_NEGATED_INT (in INTEGER_CST).
IDENTIFIER_MARKED (used by search routines).
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
+ C_MAYBE_CONST_EXPR_INT_OPERANDS (in C_MAYBE_CONST_EXPR, for C)
1: C_DECLARED_LABEL_FLAG (in LABEL_DECL)
STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST)
+ C_MAYBE_CONST_EXPR_NON_CONST (in C_MAYBE_CONST_EXPR, for C)
2: unused
3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST)
4: unused
@@ -715,6 +717,9 @@ extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree);
extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
extern bool decl_with_nonnull_addr_p (const_tree);
+extern tree c_fully_fold (tree, bool, bool *);
+extern tree decl_constant_value_for_optimization (tree);
+extern tree c_save_expr (tree);
extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (tree, bool, int);
@@ -799,6 +804,21 @@ extern void finish_file (void);
#define COMPOUND_LITERAL_EXPR_DECL(NODE) \
DECL_EXPR_DECL (COMPOUND_LITERAL_EXPR_DECL_STMT (NODE))
+/* C_MAYBE_CONST_EXPR accessors. */
+#define C_MAYBE_CONST_EXPR_PRE(NODE) \
+ TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 0)
+#define C_MAYBE_CONST_EXPR_EXPR(NODE) \
+ TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 1)
+#define C_MAYBE_CONST_EXPR_INT_OPERANDS(NODE) \
+ TREE_LANG_FLAG_0 (C_MAYBE_CONST_EXPR_CHECK (NODE))
+#define C_MAYBE_CONST_EXPR_NON_CONST(NODE) \
+ TREE_LANG_FLAG_1 (C_MAYBE_CONST_EXPR_CHECK (NODE))
+#define EXPR_INT_CONST_OPERANDS(EXPR) \
+ (INTEGRAL_TYPE_P (TREE_TYPE (EXPR)) \
+ && (TREE_CODE (EXPR) == INTEGER_CST \
+ || (TREE_CODE (EXPR) == C_MAYBE_CONST_EXPR \
+ && C_MAYBE_CONST_EXPR_INT_OPERANDS (EXPR))))
+
/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */
#define DECL_C_BIT_FIELD(NODE) \
(DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
diff --git a/gcc/c-convert.c b/gcc/c-convert.c
index d7e2e5d04bc..f6bf5deb893 100644
--- a/gcc/c-convert.c
+++ b/gcc/c-convert.c
@@ -1,6 +1,6 @@
/* Language-level data type conversion for GNU C.
- Copyright (C) 1987, 1988, 1991, 1998, 2002, 2003, 2004, 2005, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1991, 1998, 2002, 2003, 2004, 2005, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
This file is part of GCC.
@@ -86,6 +86,8 @@ convert (tree type, tree expr)
if (type == TREE_TYPE (expr))
return expr;
+ STRIP_TYPE_NOPS (e);
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
return fold_convert (type, expr);
if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 885fcddc620..588b75c5527 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -410,8 +410,8 @@ static tree lookup_name_in_scope (tree, struct c_scope *);
static tree c_make_fname_decl (tree, int);
static tree grokdeclarator (const struct c_declarator *,
struct c_declspecs *,
- enum decl_context, bool, tree *, tree *,
- enum deprecated_states);
+ enum decl_context, bool, tree *, tree *, tree *,
+ bool *, enum deprecated_states);
static tree grokparms (struct c_arg_info *, bool);
static void layout_array_type (tree);
@@ -3128,10 +3128,15 @@ add_flexible_array_elts_to_size (tree decl, tree init)
}
}
-/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
+/* Decode a "typename", such as "int **", returning a ..._TYPE node.
+ Set *EXPR, if EXPR not NULL, to any expression to be evaluated
+ before the type name, and set *EXPR_CONST_OPERANDS, if
+ EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may
+ appear in a constant expression. */
tree
-groktypename (struct c_type_name *type_name)
+groktypename (struct c_type_name *type_name, tree *expr,
+ bool *expr_const_operands)
{
tree type;
tree attrs = type_name->specs->attrs;
@@ -3139,7 +3144,8 @@ groktypename (struct c_type_name *type_name)
type_name->specs->attrs = NULL_TREE;
type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
- false, NULL, &attrs, DEPRECATED_NORMAL);
+ false, NULL, &attrs, expr, expr_const_operands,
+ DEPRECATED_NORMAL);
/* Apply attributes. */
decl_attributes (&type, attrs, 0);
@@ -3168,6 +3174,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
{
tree decl;
tree tem;
+ tree expr = NULL_TREE;
enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
/* An object declared as __attribute__((deprecated)) suppresses
@@ -3176,11 +3183,14 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
deprecated_state = DEPRECATED_SUPPRESS;
decl = grokdeclarator (declarator, declspecs,
- NORMAL, initialized, NULL, &attributes,
+ NORMAL, initialized, NULL, &attributes, &expr, NULL,
deprecated_state);
if (!decl)
return 0;
+ if (expr)
+ add_stmt (expr);
+
if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
@@ -3668,7 +3678,7 @@ grokparm (const struct c_parm *parm)
{
tree attrs = parm->attrs;
tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
- NULL, &attrs, DEPRECATED_NORMAL);
+ NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
@@ -3685,7 +3695,7 @@ push_parm_decl (const struct c_parm *parm)
tree decl;
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
- &attrs, DEPRECATED_NORMAL);
+ &attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
decl = pushdecl (decl);
@@ -3716,10 +3726,11 @@ mark_forward_parm_decls (void)
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
- literal. */
+ literal. NON_CONST is true if the initializers contain something
+ that cannot occur in a constant expression. */
tree
-build_compound_literal (tree type, tree init)
+build_compound_literal (tree type, tree init, bool non_const)
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
@@ -3772,6 +3783,12 @@ build_compound_literal (tree type, tree init)
rest_of_decl_compilation (decl, 1, 0);
}
+ if (non_const)
+ {
+ complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit);
+ C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1;
+ }
+
return complit;
}
@@ -3958,6 +3975,11 @@ warn_variable_length_array (const char *name, tree size)
DECL_ATTRS points to the list of attributes that should be added to this
decl. Any nested attributes that belong on the decl itself will be
added to this list.
+ If EXPR is not NULL, any expressions that need to be evaluated as
+ part of evaluating variably modified types will be stored in *EXPR.
+ If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be
+ set to indicate whether operands in *EXPR can be used in constant
+ expressions.
DEPRECATED_STATE is a deprecated_states value indicating whether
deprecation warnings should be suppressed.
@@ -3972,7 +3994,8 @@ static tree
grokdeclarator (const struct c_declarator *declarator,
struct c_declspecs *declspecs,
enum decl_context decl_context, bool initialized, tree *width,
- tree *decl_attrs, enum deprecated_states deprecated_state)
+ tree *decl_attrs, tree *expr, bool *expr_const_operands,
+ enum deprecated_states deprecated_state)
{
tree type = declspecs->type;
bool threadp = declspecs->thread_p;
@@ -3994,6 +4017,16 @@ grokdeclarator (const struct c_declarator *declarator,
bool bitfield = width != NULL;
tree element_type;
struct c_arg_info *arg_info = 0;
+ tree expr_dummy;
+ bool expr_const_operands_dummy;
+
+ if (expr == NULL)
+ expr = &expr_dummy;
+ if (expr_const_operands == NULL)
+ expr_const_operands = &expr_const_operands_dummy;
+
+ *expr = declspecs->expr;
+ *expr_const_operands = declspecs->expr_const_operands;
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
@@ -4306,6 +4339,11 @@ grokdeclarator (const struct c_declarator *declarator,
if (size)
{
+ bool size_maybe_const = true;
+ bool size_int_const = (TREE_CODE (size) == INTEGER_CST
+ && !TREE_OVERFLOW (size));
+ bool this_size_varies = false;
+
/* Strip NON_LVALUE_EXPRs since we aren't using as an
lvalue. */
STRIP_TYPE_NOPS (size);
@@ -4316,11 +4354,13 @@ grokdeclarator (const struct c_declarator *declarator,
size = integer_one_node;
}
- if (pedantic && integer_zerop (size))
+ size = c_fully_fold (size, false, &size_maybe_const);
+
+ if (pedantic && size_maybe_const && integer_zerop (size))
pedwarn (input_location, OPT_pedantic,
"ISO C forbids zero-size array %qs", name);
- if (TREE_CODE (size) == INTEGER_CST)
+ if (TREE_CODE (size) == INTEGER_CST && size_maybe_const)
{
constant_expression_warning (size);
if (tree_int_cst_sgn (size) < 0)
@@ -4328,6 +4368,13 @@ grokdeclarator (const struct c_declarator *declarator,
error ("size of array %qs is negative", name);
size = integer_one_node;
}
+ /* Handle a size folded to an integer constant but
+ not an integer constant expression. */
+ if (!size_int_const)
+ {
+ this_size_varies = size_varies = 1;
+ warn_variable_length_array (orig_name, size);
+ }
}
else if ((decl_context == NORMAL || decl_context == FIELD)
&& current_scope == file_scope)
@@ -4340,11 +4387,11 @@ grokdeclarator (const struct c_declarator *declarator,
/* Make sure the array size remains visibly
nonconstant even if it is (eg) a const variable
with known value. */
- size_varies = 1;
+ this_size_varies = size_varies = 1;
warn_variable_length_array (orig_name, size);
}
- if (integer_zerop (size))
+ if (integer_zerop (size) && !this_size_varies)
{
/* A zero-length array cannot be represented with
an unsigned index type, which is what we'll
@@ -4359,6 +4406,9 @@ grokdeclarator (const struct c_declarator *declarator,
with the +1 that happens when building TYPE_SIZE. */
if (size_varies)
size = variable_size (size);
+ if (this_size_varies && TREE_CODE (size) == INTEGER_CST)
+ size = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+ integer_zero_node, size);
/* Compute the maximum valid index, that is, size
- 1. Do the calculation in index_type, so that
@@ -4386,6 +4436,15 @@ grokdeclarator (const struct c_declarator *declarator,
itype = build_index_type (itype);
}
+ if (this_size_varies)
+ {
+ if (*expr)
+ *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+ *expr, size);
+ else
+ *expr = size;
+ *expr_const_operands &= size_maybe_const;
+ }
}
else if (decl_context == FIELD)
{
@@ -5288,10 +5347,15 @@ struct c_typespec
parser_xref_tag (enum tree_code code, tree name)
{
struct c_typespec ret;
+ tree ref;
+
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- tree ref = lookup_tag (code, name, 0);
+ ref = lookup_tag (code, name, 0);
/* If this is the right type of tag, return what we found.
(This reference will be shadowed by shadow_tag later if appropriate.)
If this is the wrong type of tag, do not return it. If it was the
@@ -5460,7 +5524,7 @@ grokfield (location_t loc,
}
value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ? &width : NULL, decl_attrs,
+ width ? &width : NULL, decl_attrs, NULL, NULL,
DEPRECATED_NORMAL);
finish_decl (value, NULL_TREE, NULL_TREE);
@@ -6119,7 +6183,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
c_break_label = c_cont_label = size_zero_node;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
- &attributes, DEPRECATED_NORMAL);
+ &attributes, NULL, NULL, DEPRECATED_NORMAL);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
@@ -7132,10 +7196,12 @@ build_null_declspecs (void)
{
struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
ret->type = 0;
+ ret->expr = 0;
ret->decl_attr = 0;
ret->attrs = 0;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
+ ret->expr_const_operands = true;
ret->declspecs_seen_p = false;
ret->type_seen_p = false;
ret->non_sc_seen_p = false;
@@ -7657,7 +7723,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
specs->tag_defined_p = true;
if (spec.kind == ctsk_typeof)
- specs->typedef_p = true;
+ {
+ specs->typedef_p = true;
+ if (spec.expr)
+ {
+ if (specs->expr)
+ specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr),
+ specs->expr, spec.expr);
+ else
+ specs->expr = spec.expr;
+ specs->expr_const_operands &= spec.expr_const_operands;
+ }
+ }
specs->type = type;
}
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index f910128de3f..4d1b4d51395 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -915,7 +915,7 @@ static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
struct c_expr);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
-static tree c_parser_expr_list (c_parser *, bool);
+static tree c_parser_expr_list (c_parser *, bool, bool);
static void c_parser_omp_construct (c_parser *);
static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
@@ -1455,6 +1455,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
/* For a typedef name, record the meaning, not the name.
In case of 'foo foo, bar;'. */
t.spec = lookup_name (value);
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
}
else
{
@@ -1464,6 +1466,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
t.spec = objc_get_protocol_qualified_type (value, proto);
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
}
declspecs_add_type (specs, t);
continue;
@@ -1479,6 +1483,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
proto = c_parser_objc_protocol_refs (parser);
t.kind = ctsk_objc;
t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
declspecs_add_type (specs, t);
continue;
}
@@ -1526,6 +1532,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
parser->objc_need_raw_identifier = true;
t.kind = ctsk_resword;
t.spec = c_parser_peek_token (parser)->value;
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
declspecs_add_type (specs, t);
c_parser_consume_token (parser);
break;
@@ -1687,6 +1695,8 @@ c_parser_enum_specifier (c_parser *parser)
ret.spec = finish_enum (type, nreverse (values),
chainon (attrs, postfix_attrs));
ret.kind = ctsk_tagdef;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
return ret;
}
else if (!ident)
@@ -1694,6 +1704,8 @@ c_parser_enum_specifier (c_parser *parser)
c_parser_error (parser, "expected %<{%>");
ret.spec = error_mark_node;
ret.kind = ctsk_tagref;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
return ret;
}
ret = parser_xref_tag (ENUMERAL_TYPE, ident);
@@ -1870,6 +1882,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
ret.spec = finish_struct (type, nreverse (contents),
chainon (attrs, postfix_attrs));
ret.kind = ctsk_tagdef;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
return ret;
}
else if (!ident)
@@ -1877,6 +1891,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
c_parser_error (parser, "expected %<{%>");
ret.spec = error_mark_node;
ret.kind = ctsk_tagref;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
return ret;
}
ret = parser_xref_tag (code, ident);
@@ -2053,6 +2069,8 @@ c_parser_typeof_specifier (c_parser *parser)
struct c_typespec ret;
ret.kind = ctsk_typeof;
ret.spec = error_mark_node;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
c_parser_consume_token (parser);
skip_evaluation++;
@@ -2070,7 +2088,7 @@ c_parser_typeof_specifier (c_parser *parser)
in_typeof--;
if (type != NULL)
{
- ret.spec = groktypename (type);
+ ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands);
pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
}
}
@@ -2086,22 +2104,10 @@ c_parser_typeof_specifier (c_parser *parser)
error_at (here, "%<typeof%> applied to a bit-field");
ret.spec = TREE_TYPE (expr.value);
was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
- /* This should be returned with the type so that when the type
- is evaluated, this can be evaluated. For now, we avoid
- evaluation when the context might. */
- if (!skip_evaluation && was_vm)
- {
- tree e = expr.value;
-
- /* If the expression is not of a type to which we cannot assign a line
- number, wrap the thing in a no-op NOP_EXPR. */
- if (DECL_P (e) || CONSTANT_CLASS_P (e))
- e = build1 (NOP_EXPR, void_type_node, e);
-
- protected_set_expr_location (e, here);
-
- add_stmt (e);
- }
+ /* This is returned with the type so that when the type is
+ evaluated, this can be evaluated. */
+ if (was_vm)
+ ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
pop_maybe_used (was_vm);
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -2858,7 +2864,8 @@ c_parser_attributes (c_parser *parser)
{
c_parser_consume_token (parser);
attr_args = tree_cons (NULL_TREE, arg1,
- c_parser_expr_list (parser, false));
+ c_parser_expr_list (parser, false,
+ true));
}
}
else
@@ -2866,7 +2873,7 @@ c_parser_attributes (c_parser *parser)
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
attr_args = NULL_TREE;
else
- attr_args = c_parser_expr_list (parser, false);
+ attr_args = c_parser_expr_list (parser, false, true);
}
attr = build_tree_list (attr_name, attr_args);
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@@ -3748,8 +3755,9 @@ c_parser_statement_after_labels (c_parser *parser)
}
else
{
- stmt
- = objc_build_throw_stmt (c_parser_expression (parser).value);
+ tree expr = c_parser_expression (parser).value;
+ expr = c_fully_fold (expr, false, NULL);
+ stmt = objc_build_throw_stmt (expr);
goto expect_semicolon;
}
break;
@@ -3810,8 +3818,9 @@ c_parser_condition (c_parser *parser)
location_t loc;
tree cond;
loc = c_parser_peek_token (parser)->location;
- cond = c_objc_common_truthvalue_conversion
- (loc, c_parser_expression_conv (parser).value);
+ cond = c_parser_expression_conv (parser).value;
+ cond = c_objc_common_truthvalue_conversion (loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
protected_set_expr_location (cond, loc);
if (warn_sequence_point)
verify_sequence_points (cond);
@@ -4304,6 +4313,7 @@ c_parser_asm_operands (c_parser *parser, bool convert_p)
expr = c_parser_expression (parser);
if (convert_p)
expr = default_function_array_conversion (expr);
+ expr.value = c_fully_fold (expr.value, false, NULL);
parser->lex_untranslated_string = true;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
{
@@ -4458,7 +4468,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C forbids omitting the middle term of a ?: expression");
/* Make sure first operand is calculated only once. */
- exp1.value = save_expr (default_conversion (cond.value));
+ exp1.value = c_save_expr (default_conversion (cond.value));
cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
skip_evaluation += cond.value == truthvalue_true_node;
}
@@ -4482,7 +4492,9 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
exp2 = c_parser_conditional_expression (parser, NULL);
exp2 = default_function_array_conversion (exp2);
skip_evaluation -= cond.value == truthvalue_true_node;
- ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
+ ret.value = build_conditional_expr (cond.value,
+ cond.original_code == C_MAYBE_CONST_EXPR,
+ exp1.value, exp2.value);
ret.original_code = ERROR_MARK;
return ret;
}
@@ -5012,7 +5024,7 @@ c_parser_alignof_expression (c_parser *parser)
/* alignof ( type-name ). */
skip_evaluation--;
in_alignof--;
- ret.value = c_alignof (groktypename (type_name));
+ ret.value = c_alignof (groktypename (type_name, NULL, NULL));
ret.original_code = ERROR_MARK;
return ret;
}
@@ -5200,7 +5212,8 @@ c_parser_postfix_expression (c_parser *parser)
expr = c_parser_expression (parser);
if (TREE_CODE (expr.value) == MODIFY_EXPR)
TREE_NO_WARNING (expr.value) = 1;
- expr.original_code = ERROR_MARK;
+ if (expr.original_code != C_MAYBE_CONST_EXPR)
+ expr.original_code = ERROR_MARK;
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
}
@@ -5226,6 +5239,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
e1 = c_parser_expr_no_commas (parser, NULL);
+ e1.value = c_fully_fold (e1.value, false, NULL);
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
@@ -5243,7 +5257,17 @@ c_parser_postfix_expression (c_parser *parser)
}
else
{
- expr.value = build_va_arg (e1.value, groktypename (t1));
+ tree type_expr = NULL_TREE;
+ expr.value = build_va_arg (e1.value, groktypename (t1,
+ &type_expr,
+ NULL));
+ if (type_expr)
+ {
+ expr.value = build2 (C_MAYBE_CONST_EXPR,
+ TREE_TYPE (expr.value), type_expr,
+ expr.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
+ }
expr.original_code = ERROR_MARK;
}
break;
@@ -5270,7 +5294,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
{
- tree type = groktypename (t1);
+ tree type = groktypename (t1, NULL, NULL);
tree offsetof_ref;
if (type == error_mark_node)
offsetof_ref = error_mark_node;
@@ -5319,6 +5343,7 @@ c_parser_postfix_expression (c_parser *parser)
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
idx = c_parser_expression (parser).value;
+ idx = c_fully_fold (idx, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
@@ -5365,10 +5390,12 @@ c_parser_postfix_expression (c_parser *parser)
tree c;
c = fold (e1.value);
- if (TREE_CODE (c) != INTEGER_CST)
+ if (TREE_CODE (c) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (c)))
error_at (loc,
"first argument to %<__builtin_choose_expr%> not"
" a constant");
+ constant_expression_warning (c);
expr = integer_zerop (c) ? e3 : e2;
}
break;
@@ -5406,8 +5433,8 @@ c_parser_postfix_expression (c_parser *parser)
{
tree e1, e2;
- e1 = TYPE_MAIN_VARIANT (groktypename (t1));
- e2 = TYPE_MAIN_VARIANT (groktypename (t2));
+ e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL));
+ e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL));
expr.value = comptypes (e1, e2)
? build_int_cst (NULL_TREE, 1)
@@ -5479,7 +5506,7 @@ c_parser_postfix_expression (c_parser *parser)
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
{
- tree type = groktypename (t1);
+ tree type = groktypename (t1, NULL, NULL);
expr.value = objc_build_encode_expr (type);
expr.original_code = ERROR_MARK;
}
@@ -5529,10 +5556,13 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
{
tree type;
struct c_expr init;
+ bool non_const;
struct c_expr expr;
location_t start_loc;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
start_init (NULL_TREE, NULL, 0);
- type = groktypename (type_name);
+ type = groktypename (type_name, &type_expr, &type_expr_const);
start_loc = c_parser_peek_token (parser)->location;
if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
{
@@ -5545,8 +5575,26 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
if (!flag_isoc99)
pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
- expr.value = build_compound_literal (type, init.value);
+ non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
+ ? CONSTRUCTOR_NON_CONST (init.value)
+ : init.original_code == C_MAYBE_CONST_EXPR);
+ non_const |= !type_expr_const;
+ expr.value = build_compound_literal (type, init.value, non_const);
expr.original_code = ERROR_MARK;
+ if (type_expr)
+ {
+ if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR)
+ {
+ gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE);
+ C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr;
+ }
+ else
+ {
+ gcc_assert (!non_const);
+ expr.value = build2 (C_MAYBE_CONST_EXPR, type,
+ type_expr, expr.value);
+ }
+ }
return c_parser_postfix_expression_after_primary (parser, expr);
}
@@ -5557,6 +5605,7 @@ static struct c_expr
c_parser_postfix_expression_after_primary (c_parser *parser,
struct c_expr expr)
{
+ struct c_expr orig_expr;
tree ident, idx, exprlist;
location_t loc = c_parser_peek_token (parser)->location;
while (true)
@@ -5579,11 +5628,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
exprlist = NULL_TREE;
else
- exprlist = c_parser_expr_list (parser, true);
+ exprlist = c_parser_expr_list (parser, true, false);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
+ orig_expr = expr;
expr.value = build_function_call (expr.value, exprlist);
expr.original_code = ERROR_MARK;
+ if (TREE_CODE (expr.value) == INTEGER_CST
+ && TREE_CODE (orig_expr.value) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
+ expr.original_code = C_MAYBE_CONST_EXPR;
break;
case CPP_DOT:
/* Structure element reference. */
@@ -5681,7 +5736,7 @@ c_parser_expression_conv (c_parser *parser)
}
/* Parse a non-empty list of expressions. If CONVERT_P, convert
- functions and arrays to pointers.
+ functions and arrays to pointers. If FOLD_P, fold the expressions.
nonempty-expr-list:
assignment-expression
@@ -5689,13 +5744,15 @@ c_parser_expression_conv (c_parser *parser)
*/
static tree
-c_parser_expr_list (c_parser *parser, bool convert_p)
+c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p)
{
struct c_expr expr;
tree ret, cur;
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
expr = default_function_array_conversion (expr);
+ if (fold_p)
+ expr.value = c_fully_fold (expr.value, false, NULL);
ret = cur = build_tree_list (NULL_TREE, expr.value);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
@@ -5703,6 +5760,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p)
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
expr = default_function_array_conversion (expr);
+ if (fold_p)
+ expr.value = c_fully_fold (expr.value, false, NULL);
cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
}
return ret;
@@ -6288,7 +6347,7 @@ c_parser_objc_type_name (c_parser *parser)
if (c_parser_next_token_starts_typename (parser))
type_name = c_parser_type_name (parser);
if (type_name)
- type = groktypename (type_name);
+ type = groktypename (type_name, NULL, NULL);
return build_tree_list (quals, type);
}
@@ -6394,6 +6453,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
expr = c_parser_expression (parser).value;
+ expr = c_fully_fold (expr, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
else
@@ -6529,7 +6589,7 @@ c_parser_objc_receiver (c_parser *parser)
c_parser_consume_token (parser);
return objc_get_class_reference (id);
}
- return c_parser_expression (parser).value;
+ return c_fully_fold (c_parser_expression (parser).value, false, NULL);
}
/* Parse objc-message-args.
@@ -6577,7 +6637,7 @@ c_parser_objc_message_args (c_parser *parser)
static tree
c_parser_objc_keywordexpr (c_parser *parser)
{
- tree list = c_parser_expr_list (parser, true);
+ tree list = c_parser_expr_list (parser, true, true);
if (TREE_CHAIN (list) == NULL_TREE)
{
/* Just return the expression, remove a level of
@@ -7053,6 +7113,7 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list)
{
location_t expr_loc = c_parser_peek_token (parser)->location;
tree c, t = c_parser_expression (parser).value;
+ t = c_fully_fold (t, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -7231,6 +7292,7 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list)
here = c_parser_peek_token (parser)->location;
t = c_parser_expr_no_commas (parser, NULL).value;
+ t = c_fully_fold (t, false, NULL);
if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
error_at (here, "schedule %<runtime%> does not take "
@@ -7430,6 +7492,7 @@ c_parser_omp_atomic (c_parser *parser)
c_parser_skip_to_pragma_eol (parser);
lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
switch (TREE_CODE (lhs))
{
case ERROR_MARK:
@@ -7491,6 +7554,7 @@ c_parser_omp_atomic (c_parser *parser)
rhs_expr = c_parser_expression (parser);
rhs_expr = default_function_array_conversion (rhs_expr);
rhs = rhs_expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
break;
}
stmt = c_finish_omp_atomic (code, lhs, rhs);
@@ -7654,6 +7718,7 @@ c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
cond = cond_expr.value;
cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
switch (cond_expr.original_code)
{
case GT_EXPR:
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index aedf191c37a..f9e4b3e5d9d 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -146,6 +146,10 @@ struct lang_type GTY(())
without prototypes. */
#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE)
+/* For a CONSTRUCTOR, whether some initializer contains a
+ subexpression meaning it is not a constant expression. */
+#define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
+
/* Record parser information about an expression that is irrelevant
for code generation alongside a tree representing its value. */
struct c_expr
@@ -154,7 +158,9 @@ struct c_expr
tree value;
/* Record the original unary/binary operator of an expression, which may
have been changed by fold, STRING_CST for unparenthesized string
- constants, or ERROR_MARK for other expressions (including
+ constants, C_MAYBE_CONST_EXPR for __builtin_constant_p calls
+ (even if parenthesized), for subexpressions, and for non-constant
+ initializers, or ERROR_MARK for other expressions (including
parenthesized expressions). */
enum tree_code original_code;
};
@@ -190,6 +196,18 @@ struct c_typespec {
enum c_typespec_kind kind;
/* The specifier itself. */
tree spec;
+ /* An expression to be evaluated before the type specifier, in the
+ case of typeof specifiers, or NULL otherwise or if no such
+ expression is required for a particular typeof specifier. In
+ particular, when typeof is applied to an expression of variably
+ modified type, that expression must be evaluated in order to
+ determine array sizes that form part of the type, but the
+ expression itself (as opposed to the array sizes) forms no part
+ of the type and so needs to be recorded separately. */
+ tree expr;
+ /* Whether the expression has operands suitable for use in constant
+ expressions. */
+ bool expr_const_operands;
};
/* A storage class specifier. */
@@ -227,6 +245,9 @@ struct c_declspecs {
whole type, or NULL_TREE if none or a keyword such as "void" or
"char" is used. Does not include qualifiers. */
tree type;
+ /* Any expression to be evaluated before the type, from a typeof
+ specifier. */
+ tree expr;
/* The attributes from a typedef decl. */
tree decl_attr;
/* When parsing, the attributes. Outside the parser, this will be
@@ -238,6 +259,9 @@ struct c_declspecs {
enum c_typespec_keyword typespec_word;
/* The storage class specifier, or csc_none if none. */
enum c_storage_class storage_class;
+ /* Whether any expressions in typeof specifiers may appear in
+ constant expressions. */
+ BOOL_BITFIELD expr_const_operands : 1;
/* Whether any declaration specifiers have been seen at all. */
BOOL_BITFIELD declspecs_seen_p : 1;
/* Whether a type specifier has been seen. */
@@ -478,7 +502,7 @@ extern tree finish_struct (tree, tree, tree);
extern struct c_arg_info *get_parm_info (bool);
extern tree grokfield (location_t, struct c_declarator *,
struct c_declspecs *, tree, tree *);
-extern tree groktypename (struct c_type_name *);
+extern tree groktypename (struct c_type_name *, tree *, bool *);
extern tree grokparm (const struct c_parm *);
extern tree implicitly_declare (tree);
extern void keep_next_level (void);
@@ -532,6 +556,7 @@ extern bool c_vla_unspec_p (tree x, tree fn);
((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0))
/* in c-typeck.c */
+extern bool in_late_binary_op;
extern int in_alignof;
extern int in_sizeof;
extern int in_typeof;
@@ -561,7 +586,7 @@ extern struct c_expr parser_build_unary_op (enum tree_code, struct c_expr,
extern struct c_expr parser_build_binary_op (location_t,
enum tree_code, struct c_expr,
struct c_expr);
-extern tree build_conditional_expr (tree, tree, tree);
+extern tree build_conditional_expr (tree, bool, tree, tree);
extern tree build_compound_expr (tree, tree);
extern tree c_cast_expr (struct c_type_name *, tree);
extern tree build_c_cast (tree, tree);
@@ -577,7 +602,7 @@ extern struct c_expr pop_init_level (int);
extern void set_init_index (tree, tree);
extern void set_init_label (tree);
extern void process_init_element (struct c_expr, bool);
-extern tree build_compound_literal (tree, tree);
+extern tree build_compound_literal (tree, tree, bool);
extern tree c_start_case (tree);
extern void c_finish_case (tree);
extern tree build_asm_expr (tree, tree, tree, tree, bool);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 4b5fa0eac1e..674220ca3b0 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -54,6 +54,13 @@ enum impl_conv {
ic_return
};
+/* Whether we are building a boolean conversion inside
+ convert_for_assignment, or some other late binary operation. If
+ build_binary_op is called (from code shared with C++) in this case,
+ then the operands have already been folded and the result will not
+ be folded again, so C_MAYBE_CONST_EXPR should not be generated. */
+bool in_late_binary_op;
+
/* The level of nesting inside "__alignof__". */
int in_alignof;
@@ -79,19 +86,18 @@ static int tagged_types_tu_compatible_p (const_tree, const_tree);
static int comp_target_types (tree, tree);
static int function_types_compatible_p (const_tree, const_tree);
static int type_lists_compatible_p (const_tree, const_tree);
-static tree decl_constant_value_for_broken_optimization (tree);
static tree lookup_field (tree, tree);
static int convert_arguments (int, tree *, tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
-static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
- int);
+static tree convert_for_assignment (tree, tree, enum impl_conv, bool,
+ tree, tree, int);
static tree valid_compound_expr_initializer (tree, tree);
static void push_string (const char *);
static void push_member_name (tree);
static int spelling_length (void);
static char *print_spelling (char *);
static void warning_init (int, const char *);
-static tree digest_init (tree, tree, bool, int);
+static tree digest_init (tree, tree, bool, bool, int);
static void output_init_element (tree, bool, tree, tree, int, bool);
static void output_pending_init_elements (int);
static int set_designator (int);
@@ -122,6 +128,29 @@ null_pointer_constant_p (const_tree expr)
&& VOID_TYPE_P (TREE_TYPE (type))
&& TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
}
+
+/* EXPR may appear in an unevaluated part of an integer constant
+ expression, but not in an evaluated part. Wrap it in a
+ C_MAYBE_CONST_EXPR, or mark it with TREE_OVERFLOW if it is just an
+ INTEGER_CST and we cannot create a C_MAYBE_CONST_EXPR. */
+
+static tree
+note_integer_operands (tree expr)
+{
+ tree ret;
+ if (TREE_CODE (expr) == INTEGER_CST && in_late_binary_op)
+ {
+ ret = copy_node (expr);
+ TREE_OVERFLOW (ret) = 1;
+ }
+ else
+ {
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr);
+ C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1;
+ }
+ return ret;
+}
+
/* This is a cache to hold if two types are compatible or not. */
struct tagged_tu_seen_cache {
@@ -1568,31 +1597,6 @@ decl_constant_value (tree decl)
return decl;
}
-/* Return either DECL or its known constant value (if it has one), but
- return DECL if pedantic or DECL has mode BLKmode. This is for
- bug-compatibility with the old behavior of decl_constant_value
- (before GCC 3.0); every use of this function is a bug and it should
- be removed before GCC 3.1. It is not appropriate to use pedantic
- in a way that affects optimization, and BLKmode is probably not the
- right test for avoiding misoptimizations either. */
-
-static tree
-decl_constant_value_for_broken_optimization (tree decl)
-{
- tree ret;
-
- if (pedantic || DECL_MODE (decl) == BLKmode)
- return decl;
-
- ret = decl_constant_value (decl);
- /* 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 != decl && TREE_STATIC (decl))
- ret = unshare_expr (ret);
- return ret;
-}
-
/* Convert the array expression EXP to a pointer. */
static tree
array_to_pointer_conversion (tree exp)
@@ -1652,7 +1656,7 @@ function_to_pointer_conversion (tree exp)
/* Perform the default conversion of arrays and functions to pointers.
Return the result of converting EXP. For any other expression, just
- return EXP after removing NOPs. */
+ return EXP. */
struct c_expr
default_function_array_conversion (struct c_expr exp)
@@ -1697,9 +1701,6 @@ default_function_array_conversion (struct c_expr exp)
exp.value = function_to_pointer_conversion (exp.value);
break;
default:
- STRIP_TYPE_NOPS (exp.value);
- if (TREE_NO_WARNING (orig_exp))
- TREE_NO_WARNING (exp.value) = 1;
break;
}
@@ -1775,15 +1776,6 @@ default_conversion (tree exp)
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
- /* Replace a nonvolatile const static variable with its value unless
- it is an array, in which case we must be sure that taking the
- address of the array produces consistent results. */
- else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
- {
- exp = decl_constant_value_for_broken_optimization (exp);
- type = TREE_TYPE (exp);
- }
-
/* Strip no-op conversions. */
orig_exp = exp;
STRIP_TYPE_NOPS (exp);
@@ -2162,7 +2154,7 @@ build_array_ref (tree array, tree index, location_t loc)
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
- ret = require_complete_type (fold (rval));
+ ret = require_complete_type (rval);
protected_set_expr_location (ret, loc);
return ret;
}
@@ -2332,14 +2324,19 @@ c_expr_sizeof_expr (struct c_expr expr)
}
else
{
- ret.value = c_sizeof (TREE_TYPE (expr.value));
+ bool expr_const_operands = true;
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_sizeof (TREE_TYPE (folded_expr));
ret.original_code = ERROR_MARK;
- if (c_vla_type_p (TREE_TYPE (expr.value)))
+ if (c_vla_type_p (TREE_TYPE (folded_expr)))
{
/* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */
- ret.value = build2 (COMPOUND_EXPR, TREE_TYPE (ret.value), expr.value, ret.value);
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
}
- pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)));
}
return ret;
}
@@ -2352,9 +2349,17 @@ c_expr_sizeof_type (struct c_type_name *t)
{
tree type;
struct c_expr ret;
- type = groktypename (t);
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
ret.value = c_sizeof (type);
ret.original_code = ERROR_MARK;
+ if (type_expr && c_vla_type_p (type))
+ {
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ type_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+ }
pop_maybe_used (type != error_mark_node
? C_TYPE_VARIABLE_SIZE (type) : false);
return ret;
@@ -2399,6 +2404,8 @@ build_function_call (tree function, tree params)
expressions, like those used for ObjC messenger dispatches. */
function = objc_rewrite_function_call (function, params);
+ function = c_fully_fold (function, false, NULL);
+
fntype = TREE_TYPE (function);
if (TREE_CODE (fntype) == ERROR_MARK)
@@ -2462,7 +2469,8 @@ build_function_call (tree function, tree params)
if (AGGREGATE_TYPE_P (return_type))
rhs = build_compound_literal (return_type,
- build_constructor (return_type, 0));
+ build_constructor (return_type, 0),
+ false);
else
rhs = fold_convert (return_type, integer_zero_node);
@@ -2481,18 +2489,22 @@ build_function_call (tree function, tree params)
check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
TYPE_ARG_TYPES (fntype));
- if (require_constant_value)
+ if (name != NULL_TREE
+ && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
{
- result = fold_build_call_array_initializer (TREE_TYPE (fntype),
- function, nargs, argarray);
- if (TREE_CONSTANT (result)
- && (name == NULL_TREE
- || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
- pedwarn_init (input_location, 0, "initializer element is not constant");
+ if (require_constant_value)
+ result = fold_build_call_array_initializer (TREE_TYPE (fntype),
+ function, nargs, argarray);
+ else
+ result = fold_build_call_array (TREE_TYPE (fntype),
+ function, nargs, argarray);
+ if (TREE_CODE (result) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
+ STRIP_TYPE_NOPS (result);
}
else
- result = fold_build_call_array (TREE_TYPE (fntype),
- function, nargs, argarray);
+ result = build_call_array (TREE_TYPE (fntype),
+ function, nargs, argarray);
if (VOID_TYPE_P (TREE_TYPE (result)))
return result;
@@ -2552,6 +2564,7 @@ convert_arguments (int nargs, tree *argarray,
tree rname = function;
int argnum = parmnum + 1;
const char *invalid_func_diag;
+ bool npc;
if (type == void_type_node)
{
@@ -2565,6 +2578,8 @@ convert_arguments (int nargs, tree *argarray,
argnum -= 2;
}
+ npc = null_pointer_constant_p (val);
+ val = c_fully_fold (val, false, NULL);
STRIP_TYPE_NOPS (val);
val = require_complete_type (val);
@@ -2705,7 +2720,7 @@ convert_arguments (int nargs, tree *argarray,
}
}
- parmval = convert_for_assignment (type, val, ic_argpass,
+ parmval = convert_for_assignment (type, val, ic_argpass, npc,
fundecl, function,
parmnum + 1);
@@ -2934,6 +2949,9 @@ build_unary_op (location_t location,
tree ret = error_mark_node;
int noconvert = flag;
const char *invalid_op_diag;
+ bool int_operands;
+
+ int_operands = EXPR_INT_CONST_OPERANDS (xarg);
if (code != ADDR_EXPR)
arg = require_complete_type (arg);
@@ -3063,6 +3081,29 @@ build_unary_op (location_t location,
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
+ if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+ {
+ tree inner = build_unary_op (location, code,
+ C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+ if (inner == error_mark_node)
+ return error_mark_node;
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (arg), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+ C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1;
+ goto return_build_unary_op;
+ }
+
+ /* Complain about anything that is not a true lvalue. */
+ if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment
+ : lv_decrement)))
+ return error_mark_node;
+
+ /* Ensure the argument is fully folded inside any SAVE_EXPR. */
+ arg = c_fully_fold (arg, false, NULL);
+
/* Increment or decrement the real part of the value,
and don't change the imaginary part. */
if (typecode == COMPLEX_TYPE)
@@ -3155,13 +3196,6 @@ build_unary_op (location_t location,
inc = convert (argtype, inc);
}
- /* Complain about anything else that is not a true lvalue. */
- if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? lv_increment
- : lv_decrement)))
- return error_mark_node;
-
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
{
@@ -3215,6 +3249,20 @@ build_unary_op (location_t location,
&& !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
+ /* Move address operations inside C_MAYBE_CONST_EXPR to simplify
+ folding later. */
+ if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+ {
+ tree inner = build_unary_op (location, code,
+ C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (arg), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+ C_MAYBE_CONST_EXPR_NON_CONST (ret)
+ = C_MAYBE_CONST_EXPR_NON_CONST (arg);
+ goto return_build_unary_op;
+ }
+
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
argtype = TREE_TYPE (arg);
@@ -3260,10 +3308,19 @@ build_unary_op (location_t location,
if (argtype == 0)
argtype = TREE_TYPE (arg);
- ret = require_constant_value ? fold_build1_initializer (code, argtype, arg)
- : fold_build1 (code, argtype, arg);
+ if (TREE_CODE (arg) == INTEGER_CST)
+ ret = (require_constant_value
+ ? fold_build1_initializer (code, argtype, arg)
+ : fold_build1 (code, argtype, arg));
+ else
+ ret = build1 (code, argtype, arg);
return_build_unary_op:
gcc_assert (ret != error_mark_node);
+ if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret)
+ && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg)))
+ ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+ else if (TREE_CODE (ret) != INTEGER_CST && int_operands)
+ ret = note_integer_operands (ret);
protected_set_expr_location (ret, location);
return ret;
}
@@ -3284,6 +3341,9 @@ lvalue_p (const_tree ref)
case COMPONENT_REF:
return lvalue_p (TREE_OPERAND (ref, 0));
+ case C_MAYBE_CONST_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 1));
+
case COMPOUND_LITERAL_EXPR:
case STRING_CST:
return 1;
@@ -3426,10 +3486,14 @@ c_mark_addressable (tree exp)
}
}
-/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
+/* Build and return a conditional expression IFEXP ? OP1 : OP2. If
+ IFEXP_BCP then the condition is a call to __builtin_constant_p, and
+ if folded to an integer constant then the unselected half may
+ contain arbitrary operations not normally permitted in constant
+ expressions. */
tree
-build_conditional_expr (tree ifexp, tree op1, tree op2)
+build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
{
tree type1;
tree type2;
@@ -3437,6 +3501,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
enum tree_code code2;
tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
+ bool int_const, op1_int_operands, op2_int_operands, int_operands;
+ tree ret;
bool objc_ok;
/* Promote both alternatives. */
@@ -3487,7 +3553,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
and later code won't know it used to be different.
Do this check on the original types, so that explicit casts
will be considered, but default promotions won't. */
- if (warn_sign_compare && !skip_evaluation)
+ if (!skip_evaluation)
{
int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1));
int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2));
@@ -3501,16 +3567,47 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
all the values of the unsigned type. */
if (!TYPE_UNSIGNED (result_type))
/* OK */;
- /* Do not warn if the signed quantity is an unsuffixed
- integer literal (or some static constant expression
- involving such literals) and it is non-negative. */
- else if ((unsigned_op2
- && tree_expr_nonnegative_warnv_p (op1, &ovf))
- || (unsigned_op1
- && tree_expr_nonnegative_warnv_p (op2, &ovf)))
- /* OK */;
else
- warning (OPT_Wsign_compare, "signed and unsigned type in conditional expression");
+ {
+ bool op1_maybe_const = true;
+ bool op2_maybe_const = true;
+
+ /* Do not warn if the signed quantity is an
+ unsuffixed integer literal (or some static
+ constant expression involving such literals) and
+ it is non-negative. This warning requires the
+ operands to be folded for best results, so do
+ that folding in this case even without
+ warn_sign_compare to avoid warning options
+ possibly affecting code generation. */
+ op1 = c_fully_fold (op1, require_constant_value,
+ &op1_maybe_const);
+ op2 = c_fully_fold (op2, require_constant_value,
+ &op2_maybe_const);
+
+ if (warn_sign_compare)
+ {
+ if ((unsigned_op2
+ && tree_expr_nonnegative_warnv_p (op1, &ovf))
+ || (unsigned_op1
+ && tree_expr_nonnegative_warnv_p (op2, &ovf)))
+ /* OK */;
+ else
+ warning (OPT_Wsign_compare, "signed and unsigned type in conditional expression");
+ }
+ if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
+ {
+ op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
+ NULL, op1);
+ C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
+ }
+ if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
+ {
+ op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2),
+ NULL, op2);
+ C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const;
+ }
+ }
}
}
}
@@ -3600,7 +3697,40 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
- return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+ op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
+ if (ifexp_bcp && ifexp == truthvalue_true_node)
+ {
+ op2_int_operands = true;
+ op1 = c_fully_fold (op1, require_constant_value, NULL);
+ }
+ if (ifexp_bcp && ifexp == truthvalue_false_node)
+ {
+ op1_int_operands = true;
+ op2 = c_fully_fold (op2, require_constant_value, NULL);
+ }
+ int_const = int_operands = (EXPR_INT_CONST_OPERANDS (ifexp)
+ && op1_int_operands
+ && op2_int_operands);
+ if (int_operands)
+ {
+ int_const = ((ifexp == truthvalue_true_node
+ && TREE_CODE (orig_op1) == INTEGER_CST
+ && !TREE_OVERFLOW (orig_op1))
+ || (ifexp == truthvalue_false_node
+ && TREE_CODE (orig_op2) == INTEGER_CST
+ && !TREE_OVERFLOW (orig_op2)));
+ }
+ if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST))
+ ret = fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ else
+ {
+ ret = build3 (COND_EXPR, result_type, ifexp, op1, op2);
+ if (int_operands)
+ ret = note_integer_operands (ret);
+ }
+
+ return ret;
}
/* Return a compound expression that performs two expressions and
@@ -3609,6 +3739,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
tree
build_compound_expr (tree expr1, tree expr2)
{
+ tree ret;
+
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
@@ -3639,7 +3771,14 @@ build_compound_expr (tree expr1, tree expr2)
if (expr2 == error_mark_node)
return error_mark_node;
- return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+
+ if (flag_isoc99
+ && EXPR_INT_CONST_OPERANDS (expr1)
+ && EXPR_INT_CONST_OPERANDS (expr2))
+ ret = note_integer_operands (ret);
+
+ return ret;
}
/* Build an expression representing a cast to type TYPE of expression EXPR. */
@@ -3704,7 +3843,7 @@ build_c_cast (tree type, tree expr)
"ISO C forbids casts to union type");
t = digest_init (type,
build_constructor_single (type, field, value),
- true, 0);
+ false, true, 0);
TREE_CONSTANT (t) = TREE_CONSTANT (value);
return t;
}
@@ -3828,7 +3967,7 @@ build_c_cast (tree type, tree expr)
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
- if (TREE_CODE (value) == INTEGER_CST)
+ if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype))
{
if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue))
{
@@ -3851,6 +3990,20 @@ build_c_cast (tree type, tree expr)
if (value == expr)
value = non_lvalue (value);
+ /* Don't allow the results of casting to floating-point or complex
+ types be confused with actual constants, or casts involving
+ integer and pointer types other than direct integer-to-integer
+ and integer-to-pointer be confused with integer constant
+ expressions and null pointer constants. */
+ if (TREE_CODE (value) == REAL_CST
+ || TREE_CODE (value) == COMPLEX_CST
+ || (TREE_CODE (value) == INTEGER_CST
+ && !((TREE_CODE (expr) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+ || TREE_CODE (expr) == REAL_CST
+ || TREE_CODE (expr) == COMPLEX_CST)))
+ value = build1 (NOP_EXPR, type, value);
+
return value;
}
@@ -3859,16 +4012,25 @@ tree
c_cast_expr (struct c_type_name *type_name, tree expr)
{
tree type;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ tree ret;
int saved_wsp = warn_strict_prototypes;
/* This avoids warnings about unprototyped casts on
integers. E.g. "#define SIG_DFL (void(*)())0". */
if (TREE_CODE (expr) == INTEGER_CST)
warn_strict_prototypes = 0;
- type = groktypename (type_name);
+ type = groktypename (type_name, &type_expr, &type_expr_const);
warn_strict_prototypes = saved_wsp;
- return build_c_cast (type, expr);
+ ret = build_c_cast (type, expr);
+ if (type_expr)
+ {
+ ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const;
+ }
+ return ret;
}
/* Build an assignment expression of lvalue LHS from value RHS.
@@ -3886,6 +4048,7 @@ build_modify_expr (location_t location,
tree newrhs;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
+ bool npc;
/* Types that aren't fully specified cannot be used in assignments. */
lhs = require_complete_type (lhs);
@@ -3897,15 +4060,28 @@ build_modify_expr (location_t location,
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
- STRIP_TYPE_NOPS (rhs);
-
newrhs = rhs;
+ if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
+ {
+ tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs),
+ modifycode, rhs);
+ if (inner == error_mark_node)
+ return error_mark_node;
+ result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+ C_MAYBE_CONST_EXPR_PRE (lhs), inner);
+ gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs));
+ C_MAYBE_CONST_EXPR_NON_CONST (result) = 1;
+ protected_set_expr_location (result, location);
+ return result;
+ }
+
/* If a binary op has been requested, combine the old LHS value with the RHS
producing the value we should actually store into the LHS. */
if (modifycode != NOP_EXPR)
{
+ lhs = c_fully_fold (lhs, false, NULL);
lhs = stabilize_reference (lhs);
newrhs = build_binary_op (location,
modifycode, lhs, rhs, 1);
@@ -3943,9 +4119,12 @@ build_modify_expr (location_t location,
TREE_TYPE (lhs) = lhstype;
}
- /* Convert new value to destination type. */
+ /* Convert new value to destination type. Fold it first for the
+ sake of conversion warnings. */
- newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
+ npc = null_pointer_constant_p (newrhs);
+ newrhs = c_fully_fold (newrhs, false, NULL);
+ newrhs = convert_for_assignment (lhstype, newrhs, ic_assign, npc,
NULL_TREE, NULL_TREE, 0);
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
@@ -3975,14 +4154,15 @@ build_modify_expr (location_t location,
if (olhstype == TREE_TYPE (result))
return result;
- result = convert_for_assignment (olhstype, result, ic_assign,
+ result = convert_for_assignment (olhstype, result, ic_assign, false,
NULL_TREE, NULL_TREE, 0);
protected_set_expr_location (result, location);
return result;
}
/* Convert value RHS to type TYPE as preparation for an assignment
- to an lvalue of type TYPE.
+ to an lvalue of type TYPE. NULL_POINTER_CONSTANT says whether RHS
+ was a null pointer constant before any folding.
The real work of conversion is done by `convert'.
The purpose of this function is to generate error messages
for assignments that are not allowed in C.
@@ -3994,6 +4174,7 @@ build_modify_expr (location_t location,
static tree
convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
+ bool null_pointer_constant,
tree fundecl, tree function, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
@@ -4049,12 +4230,6 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
} \
} while (0)
- STRIP_TYPE_NOPS (rhs);
-
- if (optimize && TREE_CODE (rhs) == VAR_DECL
- && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
- rhs = decl_constant_value_for_broken_optimization (rhs);
-
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
@@ -4142,7 +4317,16 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
|| coder == FIXED_POINT_TYPE
|| coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
|| coder == BOOLEAN_TYPE))
- return convert_and_check (type, rhs);
+ {
+ tree ret;
+ bool save = in_late_binary_op;
+ if (codel == BOOLEAN_TYPE)
+ in_late_binary_op = true;
+ ret = convert_and_check (type, rhs);
+ if (codel == BOOLEAN_TYPE)
+ in_late_binary_op = save;
+ return ret;
+ }
/* Aggregates in different TUs might need conversion. */
if ((codel == RECORD_TYPE || codel == UNION_TYPE)
@@ -4197,7 +4381,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
}
/* Can convert integer zero to any pointer type. */
- if (null_pointer_constant_p (rhs))
+ if (null_pointer_constant)
{
rhs = null_pointer_node;
break;
@@ -4335,7 +4519,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
||
(VOID_TYPE_P (ttr)
- && !null_pointer_constant_p (rhs)
+ && !null_pointer_constant
&& TREE_CODE (ttl) == FUNCTION_TYPE)))
WARN_FOR_ASSIGNMENT (input_location, OPT_pedantic,
G_("ISO C forbids passing argument %d of "
@@ -4430,7 +4614,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
- if (!null_pointer_constant_p (rhs))
+ if (!null_pointer_constant)
WARN_FOR_ASSIGNMENT (input_location, 0,
G_("passing argument %d of %qE makes "
"pointer from integer without a cast"),
@@ -4457,7 +4641,14 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
return convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
- return convert (type, rhs);
+ {
+ tree ret;
+ bool save = in_late_binary_op;
+ in_late_binary_op = true;
+ ret = convert (type, rhs);
+ in_late_binary_op = save;
+ return ret;
+ }
switch (errtype)
{
@@ -4518,6 +4709,7 @@ void
store_init_value (tree decl, tree init)
{
tree value, type;
+ bool npc = false;
/* If variable's type was invalidly declared, just ignore it. */
@@ -4527,7 +4719,9 @@ store_init_value (tree decl, tree init)
/* Digest the specified initializer into an expression. */
- value = digest_init (type, init, true, TREE_STATIC (decl));
+ if (init)
+ npc = null_pointer_constant_p (init);
+ value = digest_init (type, init, npc, true, TREE_STATIC (decl));
/* Store the expression if valid; else report error. */
@@ -4758,6 +4952,8 @@ maybe_warn_string_init (tree type, struct c_expr expr)
/* Digest the parser output INIT as an initializer for type TYPE.
Return a C expression of type TYPE to represent the initial value.
+ NULL_POINTER_CONSTANT is true if INIT is a null pointer constant.
+
If INIT is a string constant, STRICT_STRING is true if it is
unparenthesized or we should not warn here for it being parenthesized.
For other types of INIT, STRICT_STRING is not used.
@@ -4766,10 +4962,12 @@ maybe_warn_string_init (tree type, struct c_expr expr)
elements are seen. */
static tree
-digest_init (tree type, tree init, bool strict_string, int require_constant)
+digest_init (tree type, tree init, bool null_pointer_constant,
+ bool strict_string, int require_constant)
{
enum tree_code code = TREE_CODE (type);
tree inside_init = init;
+ bool maybe_const = true;
if (type == error_mark_node
|| !init
@@ -4779,7 +4977,8 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
STRIP_TYPE_NOPS (inside_init);
- inside_init = fold (inside_init);
+ 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. */
@@ -4949,9 +5148,6 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
return error_mark_node;
}
- if (optimize && TREE_CODE (inside_init) == VAR_DECL)
- inside_init = decl_constant_value_for_broken_optimization (inside_init);
-
/* Compound expressions can only occur here if -pedantic or
-pedantic-errors is specified. In the later case, we always want
an error. In the former case, we simply want a warning. */
@@ -4976,11 +5172,15 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
error_init ("initializer element is not constant");
inside_init = error_mark_node;
}
+ else if (require_constant && !maybe_const)
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
/* Added to enable additional -Wmissing-format-attribute warnings. */
if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
- inside_init = convert_for_assignment (type, inside_init, ic_init, NULL_TREE,
- NULL_TREE, 0);
+ inside_init = convert_for_assignment (type, inside_init, ic_init,
+ null_pointer_constant,
+ NULL_TREE, NULL_TREE, 0);
return inside_init;
}
@@ -4993,9 +5193,10 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
&& (TREE_CODE (init) == STRING_CST
|| TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
- init = array_to_pointer_conversion (init);
+ inside_init = init = array_to_pointer_conversion (init);
inside_init
- = convert_for_assignment (type, init, ic_init,
+ = convert_for_assignment (type, inside_init, ic_init,
+ null_pointer_constant,
NULL_TREE, NULL_TREE, 0);
/* Check to see if we have already given an error message. */
@@ -5013,6 +5214,9 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
error_init ("initializer element is not computable at load time");
inside_init = error_mark_node;
}
+ else if (require_constant && !maybe_const)
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
return inside_init;
}
@@ -5072,6 +5276,10 @@ static int constructor_constant;
/* 1 if so far this constructor's elements are all valid address constants. */
static int constructor_simple;
+/* 1 if this constructor has an element that cannot be part of a
+ constant expression. */
+static int constructor_nonconst;
+
/* 1 if this constructor is erroneous so far. */
static int constructor_erroneous;
@@ -5141,6 +5349,7 @@ struct constructor_stack
struct constructor_range_stack *range_stack;
char constant;
char simple;
+ char nonconst;
char implicit;
char erroneous;
char outer;
@@ -5304,6 +5513,7 @@ really_start_incremental_init (tree type)
p->elements = constructor_elements;
p->constant = constructor_constant;
p->simple = constructor_simple;
+ p->nonconst = constructor_nonconst;
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
p->depth = constructor_depth;
@@ -5319,6 +5529,7 @@ really_start_incremental_init (tree type)
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_pending_elts = 0;
@@ -5445,6 +5656,7 @@ push_init_level (int implicit)
p->elements = constructor_elements;
p->constant = constructor_constant;
p->simple = constructor_simple;
+ p->nonconst = constructor_nonconst;
p->erroneous = constructor_erroneous;
p->pending_elts = constructor_pending_elts;
p->depth = constructor_depth;
@@ -5460,6 +5672,7 @@ push_init_level (int implicit)
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_incremental = 1;
@@ -5509,6 +5722,7 @@ push_init_level (int implicit)
{
constructor_constant = TREE_CONSTANT (value);
constructor_simple = TREE_STATIC (value);
+ constructor_nonconst = CONSTRUCTOR_NON_CONST (value);
constructor_elements = CONSTRUCTOR_ELTS (value);
if (!VEC_empty (constructor_elt, constructor_elements)
&& (TREE_CODE (constructor_type) == RECORD_TYPE
@@ -5713,9 +5927,19 @@ pop_init_level (int implicit)
TREE_CONSTANT (ret.value) = 1;
if (constructor_constant && constructor_simple)
TREE_STATIC (ret.value) = 1;
+ if (constructor_nonconst)
+ CONSTRUCTOR_NON_CONST (ret.value) = 1;
}
}
+ if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR)
+ {
+ if (constructor_nonconst)
+ ret.original_code = C_MAYBE_CONST_EXPR;
+ else if (ret.original_code == C_MAYBE_CONST_EXPR)
+ ret.original_code = ERROR_MARK;
+ }
+
constructor_type = p->type;
constructor_fields = p->fields;
constructor_index = p->index;
@@ -5726,6 +5950,7 @@ pop_init_level (int implicit)
constructor_elements = p->elements;
constructor_constant = p->constant;
constructor_simple = p->simple;
+ constructor_nonconst = p->nonconst;
constructor_erroneous = p->erroneous;
constructor_incremental = p->incremental;
constructor_designated = p->designated;
@@ -5860,6 +6085,9 @@ set_init_index (tree first, tree last)
error_init ("array index in initializer exceeds array bounds");
else
{
+ constant_expression_warning (first);
+ if (last)
+ constant_expression_warning (last);
constructor_index = convert (bitsizetype, first);
if (last)
@@ -6348,6 +6576,8 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
int pending, bool implicit)
{
constructor_elt *celt;
+ bool maybe_const = true;
+ bool npc;
if (type == error_mark_node || value == error_mark_node)
{
@@ -6374,6 +6604,9 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
value = DECL_INITIAL (decl);
}
+ npc = null_pointer_constant_p (value);
+ value = c_fully_fold (value, require_constant_value, &maybe_const);
+
if (value == error_mark_node)
constructor_erroneous = 1;
else if (!TREE_CONSTANT (value))
@@ -6384,6 +6617,8 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
&& DECL_C_BIT_FIELD (field)
&& TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
+ if (!maybe_const)
+ constructor_nonconst = 1;
if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
{
@@ -6396,6 +6631,10 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
pedwarn (input_location, 0,
"initializer element is not computable at load time");
}
+ else if (!maybe_const
+ && (require_constant_value || require_constant_elements))
+ pedwarn_init (input_location, 0,
+ "initializer element is not a constant expression");
/* If this field is empty (and not at the end of structure),
don't do anything other than checking the initializer. */
@@ -6407,12 +6646,15 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|| TREE_CHAIN (field)))))
return;
- value = digest_init (type, value, strict_string, require_constant_value);
+ value = digest_init (type, value, npc, strict_string,
+ require_constant_value);
if (value == error_mark_node)
{
constructor_erroneous = 1;
return;
}
+ if (require_constant_value || require_constant_elements)
+ constant_expression_warning (value);
/* If this element doesn't come next in sequence,
put it on constructor_pending_elts. */
@@ -6718,7 +6960,7 @@ process_init_element (struct c_expr value, bool implicit)
if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
|| !require_constant_value
|| flag_isoc99)
- value.value = save_expr (value.value);
+ value.value = c_save_expr (value.value);
}
while (1)
@@ -7191,6 +7433,7 @@ tree
c_finish_goto_ptr (tree expr)
{
pedwarn (input_location, OPT_pedantic, "ISO C forbids %<goto *expr;%>");
+ expr = c_fully_fold (expr, false, NULL);
expr = convert (ptr_type_node, expr);
return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
@@ -7203,10 +7446,17 @@ c_finish_return (tree retval)
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt;
bool no_warning = false;
+ bool npc = false;
if (TREE_THIS_VOLATILE (current_function_decl))
warning (0, "function declared %<noreturn%> has a %<return%> statement");
+ if (retval)
+ {
+ npc = null_pointer_constant_p (retval);
+ retval = c_fully_fold (retval, false, NULL);
+ }
+
if (!retval)
{
current_function_returns_null = 1;
@@ -7231,7 +7481,7 @@ c_finish_return (tree retval)
}
else
{
- tree t = convert_for_assignment (valtype, retval, ic_return,
+ tree t = convert_for_assignment (valtype, retval, ic_return, npc,
NULL_TREE, NULL_TREE, 0);
tree res = DECL_RESULT (current_function_decl);
tree inner;
@@ -7375,6 +7625,7 @@ c_start_case (tree exp)
warning (OPT_Wtraditional, "%<long%> switch expression not "
"converted to %<int%> in ISO C");
+ exp = c_fully_fold (exp, false, NULL);
exp = default_conversion (exp);
if (warn_sequence_point)
@@ -7668,6 +7919,8 @@ c_process_expr_stmt (tree expr)
if (!expr)
return NULL_TREE;
+ expr = c_fully_fold (expr, false, NULL);
+
if (warn_sequence_point)
verify_sequence_points (expr);
@@ -7823,10 +8076,13 @@ c_finish_stmt_expr (tree body)
|| (last == BIND_EXPR_BODY (body)
&& BIND_EXPR_VARS (body) == NULL))
{
+ /* Even if this looks constant, do not allow it in a constant
+ expression. */
+ last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
+ C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
/* Do not warn if the return value of a statement expression is
unused. */
- if (CAN_HAVE_LOCATION_P (last))
- TREE_NO_WARNING (last) = 1;
+ TREE_NO_WARNING (last) = 1;
return last;
}
@@ -8018,6 +8274,7 @@ build_binary_op (location_t location, enum tree_code code,
tree op0, op1;
tree ret = error_mark_node;
const char *invalid_op_diag;
+ bool int_const, int_const_or_overflow, int_operands;
/* Expression code to give to the expression when it is built.
Normally this is CODE, which is what the caller asked for,
@@ -8067,6 +8324,19 @@ build_binary_op (location_t location, enum tree_code code,
if (location == UNKNOWN_LOCATION)
location = input_location;
+ int_operands = (EXPR_INT_CONST_OPERANDS (orig_op0)
+ && EXPR_INT_CONST_OPERANDS (orig_op1));
+ if (int_operands)
+ {
+ int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST
+ && TREE_CODE (orig_op1) == INTEGER_CST);
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && !TREE_OVERFLOW (orig_op1));
+ }
+ else
+ int_const = int_const_or_overflow = false;
+
if (convert_p)
{
op0 = default_conversion (orig_op0);
@@ -8233,6 +8503,28 @@ build_binary_op (location_t location, enum tree_code code,
op1 = c_common_truthvalue_conversion (location, op1);
converted = 1;
}
+ if (code == TRUTH_ANDIF_EXPR)
+ {
+ int_const_or_overflow = (int_operands
+ && TREE_CODE (orig_op0) == INTEGER_CST
+ && (op0 == truthvalue_false_node
+ || TREE_CODE (orig_op1) == INTEGER_CST));
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && (op0 == truthvalue_false_node
+ || !TREE_OVERFLOW (orig_op1)));
+ }
+ else if (code == TRUTH_ORIF_EXPR)
+ {
+ int_const_or_overflow = (int_operands
+ && TREE_CODE (orig_op0) == INTEGER_CST
+ && (op0 == truthvalue_true_node
+ || TREE_CODE (orig_op1) == INTEGER_CST));
+ int_const = (int_const_or_overflow
+ && !TREE_OVERFLOW (orig_op0)
+ && (op0 == truthvalue_true_node
+ || !TREE_OVERFLOW (orig_op1)));
+ }
break;
/* Shift operations: result has same type as first operand;
@@ -8243,17 +8535,25 @@ build_binary_op (location_t location, enum tree_code code,
if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+ if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_sgn (op1) < 0)
- warning (0, "right shift count is negative");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "right shift count is negative");
+ }
else
{
if (!integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, "right shift count >= width of type");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "right shift count >= width of type");
+ }
}
}
@@ -8272,13 +8572,21 @@ build_binary_op (location_t location, enum tree_code code,
if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
&& code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+ if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_sgn (op1) < 0)
- warning (0, "left shift count is negative");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "left shift count is negative");
+ }
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, "left shift count >= width of type");
+ {
+ int_const = false;
+ if (skip_evaluation == 0)
+ warning (0, "left shift count >= width of type");
+ }
}
/* Use the type of the value to be shifted. */
@@ -8531,10 +8839,54 @@ build_binary_op (location_t location, enum tree_code code,
converted = 1;
resultcode = xresultcode;
- if (warn_sign_compare && !skip_evaluation)
- {
- warn_for_sign_compare (location, orig_op0, orig_op1, op0, op1,
- result_type, resultcode);
+ if (!skip_evaluation)
+ {
+ bool op0_maybe_const = true;
+ bool op1_maybe_const = true;
+ tree orig_op0_folded, orig_op1_folded;
+
+ if (in_late_binary_op)
+ {
+ orig_op0_folded = orig_op0;
+ orig_op1_folded = orig_op1;
+ }
+ else
+ {
+ /* Fold for the sake of possible warnings, as in
+ build_conditional_expr. This requires the
+ "original" values to be folded, not just op0 and
+ op1. */
+ op0 = c_fully_fold (op0, require_constant_value,
+ &op0_maybe_const);
+ op1 = c_fully_fold (op1, require_constant_value,
+ &op1_maybe_const);
+ orig_op0_folded = c_fully_fold (orig_op0,
+ require_constant_value,
+ NULL);
+ orig_op1_folded = c_fully_fold (orig_op1,
+ require_constant_value,
+ NULL);
+ }
+
+ if (warn_sign_compare)
+ warn_for_sign_compare (location, orig_op0_folded,
+ orig_op1_folded, op0, op1,
+ result_type, resultcode);
+ if (!in_late_binary_op)
+ {
+ if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
+ {
+ op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0),
+ NULL, op0);
+ C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const;
+ }
+ if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
+ {
+ op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
+ NULL, op1);
+ C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
+ }
+ }
}
}
}
@@ -8568,16 +8920,24 @@ build_binary_op (location_t location, enum tree_code code,
build_type = result_type;
/* Treat expressions in initializers specially as they can't trap. */
- ret = require_constant_value ? fold_build2_initializer (resultcode,
- build_type,
- op0, op1)
- : fold_build2 (resultcode, build_type,
- op0, op1);
+ if (int_const_or_overflow)
+ ret = (require_constant_value
+ ? fold_build2_initializer (resultcode, build_type, op0, op1)
+ : fold_build2 (resultcode, build_type, op0, op1));
+ else
+ ret = build2 (resultcode, build_type, op0, op1);
if (final_type != 0)
ret = convert (final_type, ret);
return_build_binary_op:
gcc_assert (ret != error_mark_node);
+ if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const)
+ ret = (int_operands
+ ? note_integer_operands (ret)
+ : build1 (NOP_EXPR, TREE_TYPE (ret), ret));
+ else if (TREE_CODE (ret) != INTEGER_CST && int_operands
+ && !in_late_binary_op)
+ ret = note_integer_operands (ret);
protected_set_expr_location (ret, location);
return ret;
}
@@ -8589,6 +8949,8 @@ build_binary_op (location_t location, enum tree_code code,
tree
c_objc_common_truthvalue_conversion (location_t location, tree expr)
{
+ bool int_const, int_operands;
+
switch (TREE_CODE (TREE_TYPE (expr)))
{
case ARRAY_TYPE:
@@ -8610,9 +8972,23 @@ c_objc_common_truthvalue_conversion (location_t location, tree expr)
break;
}
+ int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr));
+ int_operands = EXPR_INT_CONST_OPERANDS (expr);
+
/* ??? Should we also give an error for void and vectors rather than
leaving those to give errors later? */
- return c_common_truthvalue_conversion (location, expr);
+ expr = c_common_truthvalue_conversion (location, expr);
+
+ if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
+ {
+ if (TREE_OVERFLOW (expr))
+ return expr;
+ else
+ return note_integer_operands (expr);
+ }
+ if (TREE_CODE (expr) == INTEGER_CST && !int_const)
+ return build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+ return expr;
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0e9d739ccbc..9500feb1112 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -663,6 +663,10 @@ A @code{typeof}-construct can be used anywhere a typedef name could be
used. For example, you can use it in a declaration, in a cast, or inside
of @code{sizeof} or @code{typeof}.
+The operand of @code{typeof} is evaluated for its side effects if and
+only if it is an expression of variably modified type or the name of
+such a type.
+
@code{typeof} is often useful in conjunction with the
statements-within-expressions feature. Here is how the two together can
be used to define a safe ``maximum'' macro that operates on any
@@ -6635,9 +6639,8 @@ depending on the arguments' types. For example:
You can use the built-in function @code{__builtin_choose_expr} to
evaluate code depending on the value of a constant expression. This
-built-in function returns @var{exp1} if @var{const_exp}, which is a
-constant expression that must be able to be determined at compile time,
-is nonzero. Otherwise it returns 0.
+built-in function returns @var{exp1} if @var{const_exp}, which is an
+integer constant expression, is nonzero. Otherwise it returns 0.
This built-in function is analogous to the @samp{? :} operator in C,
except that the expression returned has its type unaltered by promotion
@@ -6716,7 +6719,11 @@ static const int table[] = @{
@noindent
This is an acceptable initializer even if @var{EXPRESSION} is not a
-constant expression. GCC must be more conservative about evaluating the
+constant expression, including the case where
+@code{__builtin_constant_p} returns 1 because @var{EXPRESSION} can be
+folded to a constant but @var{EXPRESSION} contains operands that would
+not otherwize be permitted in a static initializer (for example,
+@code{0 && foo ()}). GCC must be more conservative about evaluating the
built-in in this case, because it has no opportunity to perform
optimization.
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 66ac679f278..4a9668fef77 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,13 @@
+2009-03-29 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/456
+ PR c/5675
+ PR c/19976
+ PR c/29116
+ PR c/31871
+ PR c/35198
+ * objc-act.c (objc_finish_try_stmt): Set in_late_binary_op.
+
2008-12-05 Sebastian Pop <sebastian.pop@amd.com>
PR bootstrap/38262
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index c23fb9ecba2..df3a719ba93 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -1,6 +1,6 @@
/* Implement classes and message passing for Objective C.
- Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GCC.
@@ -3885,12 +3885,15 @@ objc_finish_try_stmt (void)
/* If we're doing Darwin setjmp exceptions, build the big nasty. */
if (flag_objc_sjlj_exceptions)
{
+ bool save = in_late_binary_op;
+ in_late_binary_op = true;
if (!cur_try_context->finally_body)
{
cur_try_context->finally_locus = input_location;
cur_try_context->end_finally_locus = input_location;
}
stmt = next_sjlj_build_try_catch_finally ();
+ in_late_binary_op = save;
}
else
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0807892c743..4588cab3d1e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,40 @@
+2009-03-29 Joseph Myers <joseph@codesourcery.com>
+
+ PR c/456
+ PR c/5675
+ PR c/19976
+ PR c/29116
+ PR c/31871
+ PR c/35198
+ * 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.
+
2009-03-29 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/forwprop-11.c: New testcase.
diff --git a/gcc/testsuite/gcc.c-torture/compile/20081108-1.c b/gcc/testsuite/gcc.c-torture/compile/20081108-1.c
new file mode 100644
index 00000000000..3209a90c83b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/20081108-1.c
@@ -0,0 +1,11 @@
+/* Test function call with function designator involving VLA
+ side-effects does not lead to an ICE. */
+
+void f (void);
+void g (void);
+
+void
+h (int a, void *b)
+{
+ ((void *)(int (*)[++a])b ? f : g) ();
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/20081108-2.c b/gcc/testsuite/gcc.c-torture/compile/20081108-2.c
new file mode 100644
index 00000000000..2f5a7f64b35
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/20081108-2.c
@@ -0,0 +1,4 @@
+/* Test boolean conversion as part of returning unsigned value does
+ not lead to an ICE. */
+
+_Bool f(unsigned a) { return a & 1; }
diff --git a/gcc/testsuite/gcc.c-torture/compile/20081108-3.c b/gcc/testsuite/gcc.c-torture/compile/20081108-3.c
new file mode 100644
index 00000000000..12c58ba98cf
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/20081108-3.c
@@ -0,0 +1,4 @@
+/* Test boolean conversion of an overflowing integer return value does
+ not lead to an ICE. */
+
+_Bool f(void) { return __INT_MAX__ + 1; }
diff --git a/gcc/testsuite/gcc.dg/bconstp-2.c b/gcc/testsuite/gcc.dg/bconstp-2.c
new file mode 100644
index 00000000000..5b5ff8b1cf1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bconstp-2.c
@@ -0,0 +1,27 @@
+/* As bconstp-1.c, but with the __builtin_constant_p calls
+ parenthesized. */
+/* { dg-do compile } */
+
+/* This test checks that builtin_constant_p can be used safely in
+ initializers for static data. The macro X() defined below should
+ be an acceptable initializer expression no matter how complex its
+ argument is. */
+
+extern int a;
+extern int b;
+
+extern int foo(void);
+extern int bar(void);
+
+#define X(exp) ((__builtin_constant_p(exp)) ? (exp) : -1)
+
+const short tests[] = {
+ X(0),
+ X(a),
+ X(0 && a),
+ X(a && b),
+ X(foo()),
+ X(0 && foo()),
+ X(a && foo()),
+ X(foo() && bar())
+};
diff --git a/gcc/testsuite/gcc.dg/bconstp-3.c b/gcc/testsuite/gcc.dg/bconstp-3.c
new file mode 100644
index 00000000000..9e3d10f3993
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bconstp-3.c
@@ -0,0 +1,27 @@
+/* As bconstp-1.c, but with the __builtin_constant_p calls inside
+ __builtin_choose_expr. */
+/* { dg-do compile } */
+
+/* This test checks that builtin_constant_p can be used safely in
+ initializers for static data. The macro X() defined below should
+ be an acceptable initializer expression no matter how complex its
+ argument is. */
+
+extern int a;
+extern int b;
+
+extern int foo(void);
+extern int bar(void);
+
+#define X(exp) (__builtin_choose_expr(1, __builtin_constant_p(exp), 1) ? (exp) : -1)
+
+const short tests[] = {
+ X(0),
+ X(a),
+ X(0 && a),
+ X(a && b),
+ X(foo()),
+ X(0 && foo()),
+ X(a && foo()),
+ X(foo() && bar())
+};
diff --git a/gcc/testsuite/gcc.dg/bconstp-4.c b/gcc/testsuite/gcc.dg/bconstp-4.c
new file mode 100644
index 00000000000..bb8aef19fc0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bconstp-4.c
@@ -0,0 +1,10 @@
+/* Test that a condition is not counted as a call to
+ __builtin_constant_p if that call is itself inside a conditional
+ expression with __builtin_constant_p condition. */
+/* { dg-do compile } */
+
+extern int foo(void);
+
+#define X(exp) (__builtin_choose_expr(1, __builtin_constant_p(exp), 1) ? (exp) : -1)
+
+const int x = ((__builtin_constant_p(1) ? __builtin_constant_p (0 && foo()) : 0) ? (0 && foo()) : -1); /* { dg-error "initializer element is not a constant expression" } */
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-1.c b/gcc/testsuite/gcc.dg/c90-const-expr-1.c
index 96d19ee8164..e4c27ac4561 100644
--- a/gcc/testsuite/gcc.dg/c90-const-expr-1.c
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-1.c
@@ -15,9 +15,9 @@ void
foo (void)
{
int i;
- static int j = (1 ? 0 : (i = 2)); /* { dg-error "initial" "assignment" { xfail *-*-* } } */
- static int k = (1 ? 0 : ++i); /* { dg-error "initial" "increment" { xfail *-*-* } } */
- static int l = (1 ? 0 : --i); /* { dg-error "initial" "decrement" { xfail *-*-* } } */
- static int m = (1 ? 0 : bar ()); /* { dg-error "initial" "function call" { xfail *-*-* } } */
- static int n = (1 ? 0 : (2, 3)); /* { dg-error "initial" "comma" { xfail *-*-* } } */
+ static int j = (1 ? 0 : (i = 2)); /* { dg-error "initial" "assignment" } */
+ static int k = (1 ? 0 : ++i); /* { dg-error "initial" "increment" } */
+ static int l = (1 ? 0 : --i); /* { dg-error "initial" "decrement" } */
+ static int m = (1 ? 0 : bar ()); /* { dg-error "initial" "function call" } */
+ static int n = (1 ? 0 : (2, 3)); /* { dg-error "initial" "comma" } */
}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-10.c b/gcc/testsuite/gcc.dg/c90-const-expr-10.c
new file mode 100644
index 00000000000..6159390bb94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-10.c
@@ -0,0 +1,28 @@
+/* Test for constant expressions: invalid null pointer constants in
+ various contexts (make sure NOPs are not inappropriately
+ stripped). */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+void *p = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+struct s { void *a; } q = { (__SIZE_TYPE__)(void *)0 }; /* { dg-error "without a cast" } */
+void *
+f (void)
+{
+ void *r;
+ r = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+ return (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+}
+void g (void *); /* { dg-message "but argument is of type" } */
+void
+h (void)
+{
+ g ((__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
+}
+void g2 (int, void *); /* { dg-message "but argument is of type" } */
+void
+h2 (void)
+{
+ g2 (0, (__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-11.c b/gcc/testsuite/gcc.dg/c90-const-expr-11.c
new file mode 100644
index 00000000000..cfda93e12a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-11.c
@@ -0,0 +1,27 @@
+/* Test for constant expressions: C90 aggregate initializers requiring
+ constant expressions. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors -O2" } */
+
+#include <float.h>
+#include <limits.h>
+
+double atan(double);
+
+struct s { double d; };
+struct t { int i; };
+
+void
+f (void)
+{
+ /* As in PR 14649 for static initializers. */
+ struct s a = { atan (1.0) }; /* { dg-error "is not a constant expression|near initialization" } */
+ /* Overflow. */
+ struct t b = { INT_MAX + 1 }; /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
+ struct t c = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 23 } */
+ /* Bad operator outside sizeof. */
+ struct s d = { 1 ? 1.0 : atan (a.d) }; /* { dg-error "is not a constant expression|near initialization" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-2.c b/gcc/testsuite/gcc.dg/c90-const-expr-2.c
index cad5bc8673b..662d8e790dc 100644
--- a/gcc/testsuite/gcc.dg/c90-const-expr-2.c
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-2.c
@@ -34,10 +34,10 @@ foo (void)
{
ASSERT_NPC (0);
ASSERT_NPC ((void *)0);
- ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(0, ZERO)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
- ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
/* This last one is a null pointer constant in C99 only. */
- ASSERT_NOT_NPC ((void *)(1 ? 0 : (0, 0))); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((void *)(1 ? ZERO : (0, ZERO))); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-3.c b/gcc/testsuite/gcc.dg/c90-const-expr-3.c
index 0fda68e82b7..46a02273445 100644
--- a/gcc/testsuite/gcc.dg/c90-const-expr-3.c
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-3.c
@@ -28,19 +28,19 @@ foo (void)
ASSERT_NPC (0);
ASSERT_NOT_NPC (ZERO);
ASSERT_NPC (0 + 0);
- ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (+0);
- ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (-0);
- ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC ((char) 0);
ASSERT_NOT_NPC ((char) ZERO);
ASSERT_NPC ((int) 0);
ASSERT_NOT_NPC ((int) ZERO);
ASSERT_NPC ((int) 0.0);
ASSERT_NOT_NPC ((int) DZERO);
- ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-6.c b/gcc/testsuite/gcc.dg/c90-const-expr-6.c
new file mode 100644
index 00000000000..50de3a9525f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-6.c
@@ -0,0 +1,53 @@
+/* Test for constant expressions: operands and casts not permitted in
+ integer constant expressions. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+/* PR 29116. */
+int n = 0, p[n * 0 + 1]; /* { dg-error "variabl|can't be evaluated" } */
+
+/* PR 31871. */
+extern int c[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */
+
+/* Implicit conversions from floating-point constants are not OK,
+ although explicit ones are. */
+extern int c1[1.0 ? 1 : 0]; /* { dg-error "variab|can't be evaluated" } */
+
+extern int c2[(int)1.0 ? 1 : 0];
+
+extern int c3[1.0 && 1]; /* { dg-error "variab|can't be evaluated" } */
+
+extern int c4[(int)1.0 && 1];
+
+extern int c5[1.0 || 1]; /* { dg-error "variab|can't be evaluated" } */
+
+extern int c6[(int)1.0 || 1];
+
+/* Similar with various other cases where integer constant expressions
+ are required. */
+
+struct s {
+ int a : (n * 0 + 1); /* { dg-error "constant" } */
+};
+
+enum e {
+ E = (1 + ((__PTRDIFF_TYPE__) (void *) 0)), /* { dg-error "constant" } */
+ E2 = 0
+};
+
+enum f {
+ F = (1 ? 1 : n), /* { dg-error "constant" } */
+ F2 = 0
+};
+
+void
+f (int a)
+{
+ int v[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */
+ switch (a)
+ {
+ case (n * 0 + 1): /* { dg-error "constant" } */
+ ;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-7.c b/gcc/testsuite/gcc.dg/c90-const-expr-7.c
new file mode 100644
index 00000000000..30aeba06a7c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-7.c
@@ -0,0 +1,35 @@
+/* Test for constant expressions: overflow and constant expressions;
+ see also overflow-warn-*.c for some other cases. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+#include <float.h>
+
+int a = DBL_MAX; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 9 } */
+int b = (int) DBL_MAX; /* { dg-error "overflow" "" } */
+unsigned int c = -1.0; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
+unsigned int d = (unsigned)-1.0; /* { dg-error "overflow" } */
+
+int e = 0 << 1000; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 16 } */
+int f = 0 << -1; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 18 } */
+int g = 0 >> 1000; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 20 } */
+int h = 0 >> -1; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 22 } */
+
+int b1 = (0 ? (int) DBL_MAX : 0);
+unsigned int d1 = (0 ? (unsigned int)-1.0 : 0);
+int e1 = (0 ? 0 << 1000 : 0);
+int f1 = (0 ? 0 << -1 : 0);
+int g1 = (0 ? 0 >> 1000 : 0);
+int h1 = (0 ? 0 >> -1: 0);
+
+int i = -1 << 0;
+
+int j[1] = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 34 } */
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-8.c b/gcc/testsuite/gcc.dg/c90-const-expr-8.c
new file mode 100644
index 00000000000..966044c4eff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-8.c
@@ -0,0 +1,27 @@
+/* Test for constant expressions: overflow and constant expressions
+ with -fwrapv: overflows still count as such for the purposes of
+ constant expressions even when they have defined values at
+ runtime. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors -fwrapv" } */
+
+#include <limits.h>
+
+enum e {
+ E0 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
+ E1 = 0 * (INT_MIN / -1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 14 } */
+ E2 = 0 * (INT_MAX * INT_MAX), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 16 } */
+ E3 = 0 * (INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 18 } */
+ E4 = 0 * (unsigned)(INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 20 } */
+ E5 = 0 * -INT_MIN, /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 22 } */
+ E6 = 0 * !-INT_MIN, /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "not an integer constant" "constant" { target *-*-* } 24 } */
+ E7 = INT_MIN % -1 /* Not an overflow. */
+};
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-9.c b/gcc/testsuite/gcc.dg/c90-const-expr-9.c
new file mode 100644
index 00000000000..d9ab3756599
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-9.c
@@ -0,0 +1,26 @@
+/* Test for constant expressions: __builtin_offsetof allowed in
+ integer constant expressions but not traditional offsetof
+ expansion. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct s {
+ int a;
+};
+
+struct t {
+ struct s a;
+ int b[2];
+};
+
+#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__) &((TYPE *)0)->MEMBER)
+
+enum e {
+ E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */
+ E2 = old_offsetof (struct t, a.a), /* { dg-error "constant" } */
+ E3 = old_offsetof (struct t, b[1]), /* { dg-error "constant" } */
+ E4 = __builtin_offsetof (struct s, a),
+ E5 = __builtin_offsetof (struct t, a.a),
+ E6 = __builtin_offsetof (struct t, b[1])
+};
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-10.c b/gcc/testsuite/gcc.dg/c99-const-expr-10.c
new file mode 100644
index 00000000000..8e5a1043d29
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-10.c
@@ -0,0 +1,28 @@
+/* Test for constant expressions: invalid null pointer constants in
+ various contexts (make sure NOPs are not inappropriately
+ stripped). */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+void *p = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+struct s { void *a; } q = { (__SIZE_TYPE__)(void *)0 }; /* { dg-error "without a cast" } */
+void *
+f (void)
+{
+ void *r;
+ r = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+ return (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
+}
+void g (void *); /* { dg-message "but argument is of type" } */
+void
+h (void)
+{
+ g ((__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
+}
+void g2 (int, void *); /* { dg-message "but argument is of type" } */
+void
+h2 (void)
+{
+ g2 (0, (__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-11.c b/gcc/testsuite/gcc.dg/c99-const-expr-11.c
new file mode 100644
index 00000000000..21d9c5f46a2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-11.c
@@ -0,0 +1,46 @@
+/* Test for constant expressions: cases involving VLAs. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+/* It appears address constants may contain casts to variably modified
+ types. Whether they should be permitted was discussed in
+ <http://groups.google.com/group/comp.std.c/msg/923eee5ab690fd98>
+ <LV7g2Vy3ARF$Ew9Q@romana.davros.org>; since static pointers to VLAs
+ are definitely permitted within functions and may be initialized
+ and such initialization involves implicit conversion to a variably
+ modified type, allowing explicit casts seems appropriate. Thus,
+ GCC allows them as long as the "evaluated" size expressions do not
+ contain the various operators not permitted to be evaluated in a
+ constant expression, and as long as the result is genuinely
+ constant (meaning that pointer arithmetic using the size of the VLA
+ is generally not permitted). */
+
+static int sa[100];
+
+volatile int nv;
+
+int
+f (int m, int n)
+{
+ static int (*a1)[n] = &sa;
+ static int (*a2)[n] = (int (*)[n])sa;
+ static int (*a3)[n] = (int (*)[(int){n}])sa;
+ static int (*a4)[n] = (int (*)[(int){m++}])sa; /* { dg-error "constant" } */
+ static int (*a5)[n] = (int (*)[(int){++m}])sa; /* { dg-error "constant" } */
+ static int (*a6)[n] = (int (*)[(int){m--}])sa; /* { dg-error "constant" } */
+ static int (*a7)[n] = (int (*)[(int){--m}])sa; /* { dg-error "constant" } */
+ static int (*a8)[n] = (int (*)[(m=n)])sa; /* { dg-error "constant" } */
+ static int (*a9)[n] = (int (*)[(m+=n)])sa; /* { dg-error "constant" } */
+ static int (*a10)[n] = (int (*)[f(m,n)])sa; /* { dg-error "constant" } */
+ static int (*a11)[n] = (int (*)[(m,n)])sa; /* { dg-error "constant" } */
+ static int (*a12)[n] = (int (*)[sizeof(int[n])])sa;
+ static int (*a13)[n] = (int (*)[sizeof(int[m++])])sa; /* { dg-error "constant" } */
+ static int (*a14)[n] = (int (*)[sizeof(*a1)])sa;
+ static int (*a15)[n] = (int (*)[sizeof(*(int (*)[n])sa)])sa;
+ static int (*a16)[n] = (int (*)[sizeof(*(int (*)[m++])sa)])sa; /* { dg-error "constant" } */
+ static int (*a17)[n] = (int (*)[nv])sa;
+ typedef int (*vmt)[m++];
+ static int (*a18)[n] = (vmt)sa;
+ return n;
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-12.c b/gcc/testsuite/gcc.dg/c99-const-expr-12.c
new file mode 100644
index 00000000000..396cea51acc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-12.c
@@ -0,0 +1,23 @@
+/* Test for constant expressions: VLA size constraints. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+void
+f (int m)
+{
+ /* An array size that is a constant expression, not just an integer
+ constant expression, must be checked for being positive, but only
+ an integer constant expression makes it not a VLA (which affects
+ certain compatibility checks, in particular). */
+ int a1[0]; /* { dg-error "zero" } */
+ int a2[-1]; /* { dg-error "negative" } */
+ int a3[(int)(double)0.0]; /* { dg-error "zero" } */
+ int a4[(int)-1.0]; /* { dg-error "negative" } */
+ int a5[(int)+1.0];
+ int a6[(int)+2.0];
+ void *p = (m ? &a5 : &a6);
+ int a7[(int)1.0];
+ int a8[(int)2.0];
+ void *q = (m ? &a7 : &a8); /* { dg-error "pointer type mismatch in conditional expression" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-13.c b/gcc/testsuite/gcc.dg/c99-const-expr-13.c
new file mode 100644
index 00000000000..0ee525bec61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-13.c
@@ -0,0 +1,15 @@
+/* Test for constant expressions: VLA size constraints with
+ -frounding-math. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors -frounding-math" } */
+
+void
+f (void)
+{
+ /* With -frounding-math, presume that floating-point expressions
+ that may depend on the rounding mode do not count as arithmetic
+ constant expressions, and so arrays involving such expressions in
+ their sizes do not have the size checked for being negative. */
+ int a1[(int)(-5.0/3.0)];
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-2.c b/gcc/testsuite/gcc.dg/c99-const-expr-2.c
index 555a58c0a63..8e5a600185f 100644
--- a/gcc/testsuite/gcc.dg/c99-const-expr-2.c
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-2.c
@@ -34,10 +34,10 @@ foo (void)
{
ASSERT_NPC (0);
ASSERT_NPC ((void *)0);
- ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(0, ZERO)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
- ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
/* This last one is a null pointer constant in C99 only. */
ASSERT_NPC ((void *)(1 ? 0 : (0, 0)));
}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-3.c b/gcc/testsuite/gcc.dg/c99-const-expr-3.c
index f230603332b..9b036a32d16 100644
--- a/gcc/testsuite/gcc.dg/c99-const-expr-3.c
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-3.c
@@ -27,19 +27,19 @@ foo (void)
ASSERT_NPC (0);
ASSERT_NOT_NPC (ZERO);
ASSERT_NPC (0 + 0);
- ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (+0);
- ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (-0);
- ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC ((char) 0);
ASSERT_NOT_NPC ((char) ZERO);
ASSERT_NPC ((int) 0);
ASSERT_NOT_NPC ((int) ZERO);
ASSERT_NPC ((int) 0.0);
ASSERT_NOT_NPC ((int) DZERO);
- ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
- ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
+ ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
+ ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-6.c b/gcc/testsuite/gcc.dg/c99-const-expr-6.c
new file mode 100644
index 00000000000..1a31ddc40c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-6.c
@@ -0,0 +1,62 @@
+/* Test for constant expressions: operands and casts not permitted in
+ integer constant expressions. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+/* PR 29116. */
+int n = 0, p[n * 0 + 1]; /* { dg-error "variabl" } */
+
+/* PR 31871. */
+extern int c[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab" } */
+
+/* Implicit conversions from floating-point constants are not OK,
+ although explicit ones are. */
+extern int c1[1.0 ? 1 : 0]; /* { dg-error "variab" } */
+
+extern int c2[(int)1.0 ? 1 : 0];
+
+extern int c3[1.0 && 1]; /* { dg-error "variab" } */
+
+extern int c4[(int)1.0 && 1];
+
+extern int c5[1.0 || 1]; /* { dg-error "variab" } */
+
+extern int c6[(int)1.0 || 1];
+
+/* Similar with various other cases where integer constant expressions
+ are required. */
+
+struct s {
+ int a : (n * 0 + 1); /* { dg-error "constant" } */
+};
+
+enum e {
+ E = (1 + ((__PTRDIFF_TYPE__) (void *) 0)), /* { dg-error "constant" } */
+ E2 = 0
+};
+
+enum f {
+ F = (1 ? 1 : n), /* { dg-error "constant" } */
+ F2 = 0
+};
+
+/* Presume that a compound literal, being a reference to an anonymous
+ variable, is not allowed in an integer constant expression
+ regardless of what initializers it contains. */
+enum g {
+ G = (1 ? 1 : (int){0}), /* { dg-error "constant" } */
+ G2 = 0
+};
+
+int v[2] = { [(n * 0 + 1)] = 1 }; /* { dg-error "constant|near initialization" } */
+
+void
+f (int a)
+{
+ switch (a)
+ {
+ case (n * 0 + 1): /* { dg-error "constant" } */
+ ;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-7.c b/gcc/testsuite/gcc.dg/c99-const-expr-7.c
new file mode 100644
index 00000000000..b872077e964
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-7.c
@@ -0,0 +1,43 @@
+/* Test for constant expressions: overflow and constant expressions;
+ see also overflow-warn-*.c for some other cases. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+#include <float.h>
+#include <limits.h>
+
+int a = DBL_MAX; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 10 } */
+int b = (int) DBL_MAX; /* { dg-error "overflow" "" } */
+unsigned int c = -1.0; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 13 } */
+unsigned int d = (unsigned)-1.0; /* { dg-error "overflow" } */
+
+int e = 0 << 1000; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 17 } */
+int f = 0 << -1; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 19 } */
+int g = 0 >> 1000; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 21 } */
+int h = 0 >> -1; /* { dg-warning "shift count" } */
+/* { dg-error "constant" "constant" { target *-*-* } 23 } */
+
+int b1 = (0 ? (int) DBL_MAX : 0);
+unsigned int d1 = (0 ? (unsigned int)-1.0 : 0);
+int e1 = (0 ? 0 << 1000 : 0);
+int f1 = (0 ? 0 << -1 : 0);
+int g1 = (0 ? 0 >> 1000 : 0);
+int h1 = (0 ? 0 >> -1: 0);
+
+/* Allowed for now, but actually undefined behavior in C99. */
+int i = -1 << 0;
+
+int j[1] = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 36 } */
+
+int array[2] = { [0 * (INT_MAX + 1)] = 0 }; /* { dg-warning "integer overflow in expression" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 39 } */
+
+_Bool k = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 42 } */
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-8.c b/gcc/testsuite/gcc.dg/c99-const-expr-8.c
new file mode 100644
index 00000000000..e84fa7b4db0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-8.c
@@ -0,0 +1,27 @@
+/* Test for constant expressions: overflow and constant expressions
+ with -fwrapv: overflows still count as such for the purposes of
+ constant expressions even when they have defined values at
+ runtime. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors -fwrapv" } */
+
+#include <limits.h>
+
+enum e {
+ E0 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
+ E1 = 0 * (INT_MIN / -1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 14 } */
+ E2 = 0 * (INT_MAX * INT_MAX), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 16 } */
+ E3 = 0 * (INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 18 } */
+ E4 = 0 * (unsigned)(INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 20 } */
+ E5 = 0 * -INT_MIN, /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 22 } */
+ E6 = 0 * !-INT_MIN, /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "not an integer constant" "constant" { target *-*-* } 24 } */
+ E7 = INT_MIN % -1 /* Not an overflow. */
+};
diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-9.c b/gcc/testsuite/gcc.dg/c99-const-expr-9.c
new file mode 100644
index 00000000000..48f43edece6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c99-const-expr-9.c
@@ -0,0 +1,26 @@
+/* Test for constant expressions: __builtin_offsetof allowed in
+ integer constant expressions but not traditional offsetof
+ expansion. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+struct s {
+ int a;
+};
+
+struct t {
+ struct s a;
+ int b[2];
+};
+
+#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__) &((TYPE *)0)->MEMBER)
+
+enum e {
+ E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */
+ E2 = old_offsetof (struct t, a.a), /* { dg-error "constant" } */
+ E3 = old_offsetof (struct t, b[1]), /* { dg-error "constant" } */
+ E4 = __builtin_offsetof (struct s, a),
+ E5 = __builtin_offsetof (struct t, a.a),
+ E6 = __builtin_offsetof (struct t, b[1])
+};
diff --git a/gcc/testsuite/gcc.dg/c99-static-1.c b/gcc/testsuite/gcc.dg/c99-static-1.c
index 3c817c624d4..a138f878d92 100644
--- a/gcc/testsuite/gcc.dg/c99-static-1.c
+++ b/gcc/testsuite/gcc.dg/c99-static-1.c
@@ -27,7 +27,7 @@ static int f4(void);
void g4(void) { sizeof(int (*)[f4()]); }
/* Constraint violation (VLA). */
-static int f5(void); /* { dg-error "used but never defined" "VLA" { xfail *-*-* } } */
+static int f5(void); /* { dg-error "used but never defined" "VLA" } */
void g5(void) { sizeof(int [0 ? f5() : 1]); }
/* OK (non-constant sizeof inside constant sizeof). */
diff --git a/gcc/testsuite/gcc.dg/compare10.c b/gcc/testsuite/gcc.dg/compare10.c
new file mode 100644
index 00000000000..3b8af28bf18
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/compare10.c
@@ -0,0 +1,16 @@
+/* Test for bogus -Wsign-compare warnings that appeared when not
+ folding operands before warning. */
+/* { dg-do compile } */
+/* { dg-options "-Wsign-compare" } */
+
+int
+test_compare (int a, unsigned b)
+{
+ return (b > 8 * (a ? 4 : 8));
+}
+
+unsigned int
+test_conditional (int a, unsigned b, int c)
+{
+ return (c ? b : 8 * (a ? 4 : 8));
+}
diff --git a/gcc/testsuite/gcc.dg/gnu89-const-expr-1.c b/gcc/testsuite/gcc.dg/gnu89-const-expr-1.c
new file mode 100644
index 00000000000..ebc68859a5e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu89-const-expr-1.c
@@ -0,0 +1,47 @@
+/* Test for constant expressions: GNU extensions. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+int n;
+
+void
+f (void)
+{
+ int i = 0;
+ int a[n];
+ enum e1 {
+ /* Integer constant expressions may not contain statement
+ expressions (not a permitted operand). */
+ E1 = (1 ? 0 : ({ 0; })), /* { dg-error "constant" } */
+ /* Real and imaginary parts act like other arithmetic
+ operators. */
+ E2 = __real__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E3 = __real__ 0,
+ E4 = __imag__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E5 = __imag__ 0,
+ /* __alignof__ always constant. */
+ E6 = __alignof__ (int[n]),
+ E7 = __alignof__ (a),
+ /* __extension__ ignored for constant expression purposes. */
+ E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E9 = __extension__ 0,
+ /* Conditional expressions with omitted arguments act like the
+ standard type. */
+ E10 = (1 ? : i++), /* { dg-error "constant" } */
+ E11 = (1 ? : 0)
+ };
+ enum e2 {
+ /* Complex integer constants may be cast directly to integer
+ types, but not after further arithmetic on them. */
+ F1 = (int) (_Complex int) 2i, /* { dg-error "constant" } */
+ F2 = (int) +2i, /* { dg-error "constant" } */
+ F3 = (int) (1 + 2i), /* { dg-error "constant" } */
+ F4 = (int) 2i
+ };
+ static double dr = __real__ (1.0 + 2.0i);
+ static double di = __imag__ (1.0 + 2.0i);
+ /* Statement expressions allowed in unevaluated subexpressions in
+ initializers in gnu99 but not gnu89. */
+ static int j = (1 ? 0 : ({ 0; })); /* { dg-warning "constant expression" } */
+}
diff --git a/gcc/testsuite/gcc.dg/gnu89-const-expr-2.c b/gcc/testsuite/gcc.dg/gnu89-const-expr-2.c
new file mode 100644
index 00000000000..3395b55c733
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu89-const-expr-2.c
@@ -0,0 +1,23 @@
+/* Test for constant expressions: __builtin_choose_expr. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89 -pedantic-errors" } */
+
+#include <limits.h>
+
+int a, b, c;
+
+void
+f (void)
+{
+ /* __builtin_choose_expr acts exactly like the chosen argument for
+ all constant expression purposes. */
+ enum e {
+ E1 = __builtin_choose_expr (1, 1, ++b)
+ };
+ /* The first argument to __builtin_choose_expr must be an integer
+ constant expression. */
+ a = __builtin_choose_expr ((void *)0, b, c); /* { dg-error "constant" } */
+ a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
+}
diff --git a/gcc/testsuite/gcc.dg/gnu99-const-expr-1.c b/gcc/testsuite/gcc.dg/gnu99-const-expr-1.c
new file mode 100644
index 00000000000..dcc976e5582
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu99-const-expr-1.c
@@ -0,0 +1,47 @@
+/* Test for constant expressions: GNU extensions. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+int n;
+
+void
+f (void)
+{
+ int i = 0;
+ int a[n];
+ enum e1 {
+ /* Integer constant expressions may not contain statement
+ expressions (not a permitted operand). */
+ E1 = (1 ? 0 : ({ 0; })), /* { dg-error "constant" } */
+ /* Real and imaginary parts act like other arithmetic
+ operators. */
+ E2 = __real__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E3 = __real__ 0,
+ E4 = __imag__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E5 = __imag__ 0,
+ /* __alignof__ always constant. */
+ E6 = __alignof__ (int[n]),
+ E7 = __alignof__ (a),
+ /* __extension__ ignored for constant expression purposes. */
+ E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant" } */
+ E9 = __extension__ 0,
+ /* Conditional expressions with omitted arguments act like the
+ standard type. */
+ E10 = (1 ? : i++), /* { dg-error "constant" } */
+ E11 = (1 ? : 0)
+ };
+ enum e2 {
+ /* Complex integer constants may be cast directly to integer
+ types, but not after further arithmetic on them. */
+ F1 = (int) (_Complex int) 2i, /* { dg-error "constant" } */
+ F2 = (int) +2i, /* { dg-error "constant" } */
+ F3 = (int) (1 + 2i), /* { dg-error "constant" } */
+ F4 = (int) 2i
+ };
+ static double dr = __real__ (1.0 + 2.0i);
+ static double di = __imag__ (1.0 + 2.0i);
+ /* Statement expressions allowed in unevaluated subexpressions in
+ initializers in gnu99 but not gnu89. */
+ static int j = (1 ? 0 : ({ 0; }));
+}
diff --git a/gcc/testsuite/gcc.dg/gnu99-const-expr-2.c b/gcc/testsuite/gcc.dg/gnu99-const-expr-2.c
new file mode 100644
index 00000000000..f868c537fa2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu99-const-expr-2.c
@@ -0,0 +1,23 @@
+/* Test for constant expressions: __builtin_choose_expr. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -pedantic-errors" } */
+
+#include <limits.h>
+
+int a, b, c;
+
+void
+f (void)
+{
+ /* __builtin_choose_expr acts exactly like the chosen argument for
+ all constant expression purposes. */
+ enum e {
+ E1 = __builtin_choose_expr (1, 1, ++b)
+ };
+ /* The first argument to __builtin_choose_expr must be an integer
+ constant expression. */
+ a = __builtin_choose_expr ((void *)0, b, c); /* { dg-error "constant" } */
+ a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "integer overflow in expression" } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
+}
diff --git a/gcc/testsuite/gcc.dg/gnu99-const-expr-3.c b/gcc/testsuite/gcc.dg/gnu99-const-expr-3.c
new file mode 100644
index 00000000000..aba7da542a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu99-const-expr-3.c
@@ -0,0 +1,32 @@
+/* Test for constant expressions: cases involving VLAs and typeof. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -pedantic-errors" } */
+
+/* It appears address constants may contain casts to variably modified
+ types. Whether they should be permitted was discussed in
+ <http://groups.google.com/group/comp.std.c/msg/923eee5ab690fd98>
+ <LV7g2Vy3ARF$Ew9Q@romana.davros.org>; since static pointers to VLAs
+ are definitely permitted within functions and may be initialized
+ and such initialization involves implicit conversion to a variably
+ modified type, allowing explicit casts seems appropriate. Thus,
+ GCC allows them as long as the "evaluated" size expressions do not
+ contain the various operators not permitted to be evaluated in a
+ constant expression, and as long as the result is genuinely
+ constant (meaning that pointer arithmetic using the size of the VLA
+ is generally not permitted). */
+
+static int sa[100];
+
+int
+f (int m, int n)
+{
+ static int (*a1)[n] = &sa;
+ static int (*a2)[n] = (__typeof__(int (*)[n]))sa;
+ static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */
+ static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa;
+ static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */
+ static int (*a6)[n] = (__typeof__((int (*)[100])(int (*)[m++])sa))sa;
+ static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */
+ return n;
+}
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-1.c b/gcc/testsuite/gcc.dg/overflow-warn-1.c
index 9f763879f2d..633d70b84b5 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-1.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-1.c
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* Again, overflow in evaluated subexpression. */
E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
@@ -28,6 +28,7 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+ /* { dg-error "not an integer constant" "integer constant" { target *-*-* } 30 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
};
@@ -46,9 +47,10 @@ static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 48 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 49 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 50 } */
+/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 51 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 51 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@@ -57,6 +59,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
+ /* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 61 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
;
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-2.c b/gcc/testsuite/gcc.dg/overflow-warn-2.c
index 7da84324ad9..e8bbd24455d 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-2.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-2.c
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* Again, overflow in evaluated subexpression. */
E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
@@ -28,6 +28,7 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+ /* { dg-error "not an integer constant" "integer constant" { target *-*-* } 30 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
};
@@ -46,9 +47,10 @@ static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 48 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 49 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 50 } */
+/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 51 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 51 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@@ -57,6 +59,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
+ /* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 61 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
;
@@ -82,23 +85,23 @@ void
h2 (void)
{
fsc (SCHAR_MAX + 1);
- /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 84 } */
+ /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 87 } */
fsc (SCHAR_MIN - 1); /* { dg-warning "overflow in implicit constant conversion" } */
- /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 86 } */
+ /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 89 } */
fsc (UCHAR_MAX);
- /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 88 } */
+ /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 91 } */
fsc (UCHAR_MAX + 1); /* { dg-warning "overflow in implicit constant conversion" } */
- /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 90 } */
+ /* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 93 } */
fuc (-1);
- /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 92 } */
+ /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 95 } */
fuc (UCHAR_MAX + 1); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
- /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 94 } */
+ /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 97 } */
fuc (SCHAR_MIN);
- /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 96 } */
+ /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 99 } */
fuc (SCHAR_MIN - 1); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
- /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 98 } */
+ /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 101 } */
fuc (-UCHAR_MAX); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
- /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 100 } */
+ /* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 103 } */
}
void fui (unsigned int);
@@ -122,11 +125,11 @@ h2i (int x)
fsi (UINT_MAX); /* { dg-warning "passing argument 1 of 'fsi' as signed due to prototype" } */
si = UINT_MAX;
fui (-1);
- /* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 124 } */
+ /* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 127 } */
ui = -1;
ui = x ? -1 : 1U;
fui (INT_MIN);
- /* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 128 } */
+ /* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 131 } */
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-3.c b/gcc/testsuite/gcc.dg/overflow-warn-3.c
index 6b1dc053efd..d9a3ae430db 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-3.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-3.c
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -30,8 +30,9 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+ /* { dg-error "not an integer constant" "integer constant" { target *-*-* } 32 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
- /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 33 } */
+ /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 34 } */
};
void
@@ -45,16 +46,17 @@ f (void)
/* But this expression does need to be constant. */
static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 47 } */
+/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 48 } */
/* The first two of these involve overflow, so are not null pointer
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 53 } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 53 } */
+/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 54 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 54 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 56 } */
+/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 57 } */
+/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 57 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@@ -63,9 +65,10 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
+ /* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 67 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
- /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 67 } */
+ /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 70 } */
;
}
}
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-4.c b/gcc/testsuite/gcc.dg/overflow-warn-4.c
index 1e2518f9c73..7b7e23cef4b 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-4.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-4.c
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -30,8 +30,9 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+ /* { dg-error "not an integer constant" "integer constant" { target *-*-* } 32 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
- /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 33 } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 34 } */
};
void
@@ -45,16 +46,17 @@ f (void)
/* But this expression does need to be constant. */
static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
-/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 47 } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 48 } */
/* The first two of these involve overflow, so are not null pointer
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
-/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 53 } */
-/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 53 } */
+/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 54 } */
+/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 54 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 56 } */
+/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 57 } */
+/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 57 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@@ -63,9 +65,10 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
+ /* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 67 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
- /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 67 } */
+ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 70 } */
;
}
}
diff --git a/gcc/testsuite/gcc.dg/pr14649-1.c b/gcc/testsuite/gcc.dg/pr14649-1.c
index 83a9f570eef..34f42f08f2c 100644
--- a/gcc/testsuite/gcc.dg/pr14649-1.c
+++ b/gcc/testsuite/gcc.dg/pr14649-1.c
@@ -4,7 +4,7 @@
double atan(double);
-const double pi = 4*atan(1.0); /* { dg-warning "(not constant)|(near initialization)" } */
+const double pi = 4*atan(1.0); /* { dg-warning "not a constant expression" } */
const double ok = 4*__builtin_atan(1.0);
diff --git a/gcc/testsuite/gcc.dg/pr19984.c b/gcc/testsuite/gcc.dg/pr19984.c
index 1b61d7f76b8..5323c461fb0 100644
--- a/gcc/testsuite/gcc.dg/pr19984.c
+++ b/gcc/testsuite/gcc.dg/pr19984.c
@@ -5,7 +5,7 @@
double nan (const char *);
-const double nok = nan (""); /* { dg-warning "(not constant)|(near initialization)" } */
+const double nok = nan (""); /* { dg-warning "(not a constant)|(near initialization)" } */
const double ok = __builtin_nan ("");
diff --git a/gcc/testsuite/gcc.dg/pr25682.c b/gcc/testsuite/gcc.dg/pr25682.c
index 4118862a1ff..c99b891f8fa 100644
--- a/gcc/testsuite/gcc.dg/pr25682.c
+++ b/gcc/testsuite/gcc.dg/pr25682.c
@@ -10,10 +10,10 @@ struct S
int b;
};
-char c[(char *) &((struct S *) 0)->b - (char *) 0];
-char d[(__SIZE_TYPE__) &((struct S *) 8)->b];
-char e[sizeof (c) == __builtin_offsetof (struct S, b) ? 1 : -1];
-char f[sizeof (d) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1];
+char c[(char *) &((struct S *) 0)->b - (char *) 0]; /* { dg-error "variable-size" } */
+char d[(__SIZE_TYPE__) &((struct S *) 8)->b]; /* { dg-error "variable-size" } */
+char e[sizeof (c) == __builtin_offsetof (struct S, b) ? 1 : -1]; /* { dg-error "variably modified" } */
+char f[sizeof (d) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1]; /* { dg-error "variably modified" } */
extern void bar (char *, char *);
diff --git a/gcc/testsuite/gcc.dg/real-const-1.c b/gcc/testsuite/gcc.dg/real-const-1.c
index 3e2bbfde8fc..4c7058d17af 100644
--- a/gcc/testsuite/gcc.dg/real-const-1.c
+++ b/gcc/testsuite/gcc.dg/real-const-1.c
@@ -1,4 +1,5 @@
/* PR middle-end/21781. */
/* { dg-do compile } */
+/* { dg-options "-Wall" } */
-int f[.0e200000000 == 0?1:-1];
+int foo(void) { if (.0e200000000 == 0 ) return 1; }
diff --git a/gcc/testsuite/gcc.dg/vect/pr32230.c b/gcc/testsuite/gcc.dg/vect/pr32230.c
index ed1e7b14614..bdb290ab4ec 100644
--- a/gcc/testsuite/gcc.dg/vect/pr32230.c
+++ b/gcc/testsuite/gcc.dg/vect/pr32230.c
@@ -16,7 +16,7 @@ const_f (filter_buffer_t *buf)
int i;
for (i = 0; i < 10; i++)
- ((float*) (&((sbuf_header_t *) ((buf) == (filter_buffer_t *)&(buf)->buf[0]))->buf[0]))[i] = val;
+ ((float*) (&((sbuf_header_t *) (__PTRDIFF_TYPE__)((buf) == (filter_buffer_t *)&(buf)->buf[0]))->buf[0]))[i] = val;
}
/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vla-12.c b/gcc/testsuite/gcc.dg/vla-12.c
new file mode 100644
index 00000000000..604ea88dc2c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-12.c
@@ -0,0 +1,50 @@
+/* Test for typeof evaluation: should be at the appropriate point in
+ the containing expression rather than just adding a statement. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+extern void exit (int);
+extern void abort (void);
+
+void *p;
+
+void
+f1 (void)
+{
+ int i = 0, j = -1, k = -1;
+ /* typeof applied to expression with cast. */
+ (j = ++i), (void)(typeof ((int (*)[(k = ++i)])p))p;
+ if (j != 1 || k != 2 || i != 2)
+ abort ();
+}
+
+void
+f2 (void)
+{
+ int i = 0, j = -1, k = -1;
+ /* typeof applied to type. */
+ (j = ++i), (void)(typeof (int (*)[(k = ++i)]))p;
+ if (j != 1 || k != 2 || i != 2)
+ abort ();
+}
+
+void
+f3 (void)
+{
+ int i = 0, j = -1, k = -1;
+ void *q;
+ /* typeof applied to expression with cast that is used. */
+ (j = ++i), (void)((typeof (1 + (int (*)[(k = ++i)])p))p);
+ if (j != 1 || k != 2 || i != 2)
+ abort ();
+}
+
+int
+main (void)
+{
+ f1 ();
+ f2 ();
+ f3 ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/vla-13.c b/gcc/testsuite/gcc.dg/vla-13.c
new file mode 100644
index 00000000000..70b63059d72
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-13.c
@@ -0,0 +1,99 @@
+/* Test for VLA size evaluation; see PR 35198. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do run } */
+/* { dg-options "-std=c99" } */
+
+extern void exit (int);
+extern void abort (void);
+
+int i;
+void *p;
+
+void
+f1 (void *x, int j)
+{
+ p = (int (*)[++i])x;
+ if (i != j)
+ abort ();
+}
+
+void
+f1c (void *x, int j)
+{
+ p = (int (*)[++i]){x};
+ if (i != j)
+ abort ();
+}
+
+void
+f2 (void *x, int j)
+{
+ x = (void *)(int (*)[++i])p;
+ if (i != j)
+ abort ();
+}
+
+void
+f2c (void *x, int j)
+{
+ x = (void *)(int (*)[++i]){p};
+ if (i != j)
+ abort ();
+}
+
+void
+f3 (void *x, int j)
+{
+ (void)(int (*)[++i])p;
+ if (i != j)
+ abort ();
+}
+
+void
+f3c (void *x, int j)
+{
+ (void)(int (*)[++i]){p};
+ if (i != j)
+ abort ();
+}
+
+void
+f4 (void *x, int j)
+{
+ (int (*)[++i])p;
+ (int (*)[++i])p;
+ if (i != j)
+ abort ();
+}
+
+void
+f4c (void *x, int j)
+{
+ (int (*)[++i]){p};
+ (int (*)[++i]){p};
+ if (i != j)
+ abort ();
+}
+
+void
+f5c (void *x, int j, int k)
+{
+ (++i, f3c (x, j), (int (*)[++i]){p});
+ if (i != k)
+ abort ();
+}
+
+int
+main (void)
+{
+ f1 (p, 1);
+ f2 (p, 2);
+ f3 (p, 3);
+ f4 (p, 5);
+ f1c (p, 6);
+ f2c (p, 7);
+ f3c (p, 8);
+ f4c (p, 10);
+ f5c (p, 12, 13);
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/vla-14.c b/gcc/testsuite/gcc.dg/vla-14.c
new file mode 100644
index 00000000000..3dbb11ed1a7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-14.c
@@ -0,0 +1,33 @@
+/* Test for VLA size evaluation in va_arg. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+#include <stdarg.h>
+
+extern void exit (int);
+extern void abort (void);
+
+int a[10];
+int i = 9;
+
+void
+f (int n, ...)
+{
+ va_list ap;
+ void *p;
+ va_start (ap, n);
+ p = va_arg (ap, typeof (int (*)[++i]));
+ if (p != a)
+ abort ();
+ if (i != n)
+ abort ();
+ va_end (ap);
+}
+
+int
+main (void)
+{
+ f (10, &a);
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/vla-15.c b/gcc/testsuite/gcc.dg/vla-15.c
new file mode 100644
index 00000000000..800163bc184
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-15.c
@@ -0,0 +1,27 @@
+/* Test for VLA size evaluation in sizeof typeof. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+#include <stdarg.h>
+
+extern void exit (int);
+extern void abort (void);
+
+char a[1];
+
+void
+f1 (void)
+{
+ int i = 0;
+ int j = sizeof (typeof (*(++i, (char (*)[i])a)));
+ if (i != 1 || j != 1)
+ abort ();
+}
+
+int
+main (void)
+{
+ f1 ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/vla-16.c b/gcc/testsuite/gcc.dg/vla-16.c
new file mode 100644
index 00000000000..05e751af7a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-16.c
@@ -0,0 +1,70 @@
+/* Test for modifying and taking addresses of compound literals whose
+ variably modified types involve typeof. */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+#include <stdarg.h>
+
+extern void exit (int);
+extern void abort (void);
+
+int a[1];
+
+void
+f1 (void)
+{
+ int i = 0;
+ int (**p)[1] = &(typeof (++i, (int (*)[i])a)){&a};
+ if (*p != &a)
+ abort ();
+ if (i != 1)
+ abort ();
+}
+
+void
+f2 (void)
+{
+ int i = 0;
+ (typeof (++i, (int (*)[i])a)){&a} = 0;
+ if (i != 1)
+ abort ();
+}
+
+void
+f3 (void)
+{
+ int i = 0;
+ (typeof (++i, (int (*)[i])a)){&a} += 1;
+ if (i != 1)
+ abort ();
+}
+
+void
+f4 (void)
+{
+ int i = 0;
+ --(typeof (++i, (int (*)[i])a)){&a + 1};
+ if (i != 1)
+ abort ();
+}
+
+void
+f5 (void)
+{
+ int i = 0;
+ (typeof (++i, (int (*)[i])a)){&a}++;
+ if (i != 1)
+ abort ();
+}
+
+int
+main (void)
+{
+ f1 ();
+ f2 ();
+ f3 ();
+ f4 ();
+ f5 ();
+ exit (0);
+}