+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
+ * inclhack.def (glibc_tgmath): New fix.
+ * fixincl.x: Regenerate.
+ * tests/base/tgmath.h: New.
+
2009-03-28 Joseph Myers <joseph@codesourcery.com>
* inclhack.def (aix_syswait, exception_structure,
*
* DO NOT EDIT THIS FILE (fixincl.x)
*
- * It has been AutoGen-ed Saturday March 28, 2009 at 12:12:55 AM UTC
+ * It has been AutoGen-ed Sunday March 29, 2009 at 01:30:25 AM UTC
* From the definitions inclhack.def
* and the template file fixincl
*/
-/* DO NOT SVN-MERGE THIS FILE, EITHER Sat Mar 28 00:12:55 UTC 2009
+/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Mar 29 01:30:25 UTC 2009
*
* You must regenerate it. Use the ./genfixes script.
*
* certain ANSI-incompatible system header files which are fixed to work
* correctly with ANSI C and placed in a directory that GNU C will search.
*
- * This file contains 177 fixup descriptions.
+ * This file contains 178 fixup descriptions.
*
* See README for more information.
*
"-e", "/define[ \t]\\+PTHREAD_COND_INITIALIZER/s/{ { 0, } }/{ { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } }/",
(char*)NULL };
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Description of Glibc_Tgmath fix
+ */
+tSCC zGlibc_TgmathName[] =
+ "glibc_tgmath";
+
+/*
+ * File name selection pattern
+ */
+tSCC zGlibc_TgmathList[] =
+ "tgmath.h\0";
+/*
+ * Machine/OS name selection pattern
+ */
+#define apzGlibc_TgmathMachs (const char**)NULL
+
+/*
+ * content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_TgmathSelect0[] =
+ "\\(\\(\\(type\\) 0.25\\) && \\(\\(type\\) 0.25 - 1\\)\\)";
+
+/*
+ * content bypass pattern - skip fix if pattern found
+ */
+tSCC zGlibc_TgmathBypass0[] =
+ "__floating_type \\\\\n\
+.*__builtin_classify_type";
+
+#define GLIBC_TGMATH_TEST_CT 2
+static tTestDesc aGlibc_TgmathTests[] = {
+ { TT_NEGREP, zGlibc_TgmathBypass0, (regex_t*)NULL },
+ { TT_EGREP, zGlibc_TgmathSelect0, (regex_t*)NULL }, };
+
+/*
+ * Fix Command Arguments for Glibc_Tgmath
+ */
+static const char* apzGlibc_TgmathPatch[] = {
+ "format",
+ "(__builtin_classify_type ((type) 0) == 8 || (__builtin_classify_type ((type) 0) == 9 && __builtin_classify_type (__real__ ((type) 0)) == 8))",
+ (char*)NULL };
+
/* * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Description of Gnu_Types fix
*
* List of all fixes
*/
-#define REGEX_COUNT 221
+#define REGEX_COUNT 223
#define MACH_LIST_SIZE_LIMIT 181
-#define FIX_COUNT 177
+#define FIX_COUNT 178
/*
* Enumerate the fixes
GLIBC_C99_INLINE_3_FIXIDX,
GLIBC_C99_INLINE_4_FIXIDX,
GLIBC_MUTEX_INIT_FIXIDX,
+ GLIBC_TGMATH_FIXIDX,
GNU_TYPES_FIXIDX,
HP_INLINE_FIXIDX,
HP_SYSFILE_FIXIDX,
GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,
aGlibc_Mutex_InitTests, apzGlibc_Mutex_InitPatch, 0 },
+ { zGlibc_TgmathName, zGlibc_TgmathList,
+ apzGlibc_TgmathMachs,
+ GLIBC_TGMATH_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+ aGlibc_TgmathTests, apzGlibc_TgmathPatch, 0 },
+
{ zGnu_TypesName, zGnu_TypesList,
apzGnu_TypesMachs,
GNU_TYPES_TEST_CT, FD_MACH_IFNOT | FD_SUBROUTINE,
};
+/* glibc's tgmath.h relies on an expression that is not an integer
+ constant expression being treated as it was by GCC 4.4 and
+ earlier. */
+fix = {
+ hackname = glibc_tgmath;
+ files = tgmath.h;
+ select = '\(\(\(type\) 0.25\) && \(\(type\) 0.25 - 1\)\)';
+ bypass = "__floating_type \\\\\n.*__builtin_classify_type";
+ c_fix = format;
+ c_fix_arg = "(__builtin_classify_type ((type) 0) == 8 || (__builtin_classify_type ((type) 0) == 9 && __builtin_classify_type (__real__ ((type) 0)) == 8))";
+ test_text = "# define __floating_type(type) (((type) 0.25) && ((type) 0.25 - 1))";
+};
+
/*
* Fix these files to use the types we think they should for
* ptrdiff_t, size_t, and wchar_t.
--- /dev/null
+/* DO NOT EDIT THIS FILE.
+
+ It has been auto-edited by fixincludes from:
+
+ "fixinc/tests/inc/tgmath.h"
+
+ This had to be done to correct non-standard usages in the
+ original, manufacturer supplied header file. */
+
+
+
+#if defined( GLIBC_TGMATH_CHECK )
+# define __floating_type(type) (__builtin_classify_type ((type) 0) == 8 || (__builtin_classify_type ((type) 0) == 9 && __builtin_classify_type (__real__ ((type) 0)) == 8))
+#endif /* GLIBC_TGMATH_CHECK */
+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
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)),
if (CAN_HAVE_LOCATION_P (realret)
&& !EXPR_HAS_LOCATION (realret))
SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
- return realret;
}
return ret;
}
{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 *);
return value;
}
\f
+/* 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.
return ret;
}
\f
+/* 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. */
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,
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)
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.
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
/* 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.
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
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);
#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)
/* 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.
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)
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);
\f
}
}
\f
-/* 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;
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);
{
tree decl;
tree tem;
+ tree expr = NULL_TREE;
enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
/* An object declared as __attribute__((deprecated)) suppresses
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);
{
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);
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);
/* 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
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;
}
\f
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.
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;
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;
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);
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)
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)
/* 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
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
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)
{
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
}
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);
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. */
{
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;
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;
}
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 *);
/* 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
{
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;
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;
}
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;
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)
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);
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)
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);
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++;
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));
}
}
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 %<)%>");
{
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
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))
}
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;
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);
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 %<)%>"))
{
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;
}
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;
}
/* 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;
}
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 %<)%>");
}
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);
}
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;
break;
}
{
- tree type = groktypename (t1);
+ tree type = groktypename (t1, NULL, NULL);
tree offsetof_ref;
if (type == error_mark_node)
offsetof_ref = error_mark_node;
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);
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;
{
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)
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;
}
{
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))
{
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);
}
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)
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. */
}
/* 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
*/
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))
{
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;
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);
}
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
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.
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
{
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 %<)%>");
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 "
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:
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);
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:
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
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;
};
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. */
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
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. */
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);
((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;
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);
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);
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;
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);
&& 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;
+}
+
\f/* This is a cache to hold if two types are compatible or not. */
struct tagged_tu_seen_cache {
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)
/* 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)
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;
}
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);
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;
}
}
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;
}
{
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;
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)
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);
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;
tree rname = function;
int argnum = parmnum + 1;
const char *invalid_func_diag;
+ bool npc;
if (type == void_type_node)
{
argnum -= 2;
}
+ npc = null_pointer_constant_p (val);
+ val = c_fully_fold (val, false, NULL);
STRIP_TYPE_NOPS (val);
val = require_complete_type (val);
}
}
- parmval = convert_for_assignment (type, val, ic_argpass,
+ parmval = convert_for_assignment (type, val, ic_argpass, npc,
fundecl, function,
parmnum + 1);
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);
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)
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))
{
&& !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);
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;
}
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;
}
}
\f
-/* 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;
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. */
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));
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;
+ }
+ }
}
}
}
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;
}
\f
/* Return a compound expression that performs two expressions and
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
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. */
"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;
}
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))
{
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;
}
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;
}
\f
/* Build an assignment expression of lvalue LHS from value RHS.
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);
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);
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;
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;
}
\f
/* 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.
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);
} \
} 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);
|| 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)
}
/* Can convert integer zero to any pointer type. */
- if (null_pointer_constant_p (rhs))
+ if (null_pointer_constant)
{
rhs = null_pointer_node;
break;
&& ((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 "
/* 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"),
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)
{
store_init_value (tree decl, tree init)
{
tree value, type;
+ bool npc = false;
/* If variable's type was invalidly declared, just ignore it. */
/* 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. */
/* 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.
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
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. */
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. */
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;
}
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. */
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;
}
/* 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;
struct constructor_range_stack *range_stack;
char constant;
char simple;
+ char nonconst;
char implicit;
char erroneous;
char outer;
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;
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_pending_elts = 0;
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;
constructor_constant = 1;
constructor_simple = 1;
+ constructor_nonconst = 0;
constructor_depth = SPELLING_DEPTH ();
constructor_elements = 0;
constructor_incremental = 1;
{
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
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;
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;
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)
int pending, bool implicit)
{
constructor_elt *celt;
+ bool maybe_const = true;
+ bool npc;
if (type == error_mark_node || value == error_mark_node)
{
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))
&& 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)))
{
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. */
|| 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. */
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)
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));
}
{
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;
}
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;
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)
if (!expr)
return NULL_TREE;
+ expr = c_fully_fold (expr, false, NULL);
+
if (warn_sequence_point)
verify_sequence_points (expr);
|| (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;
}
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,
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);
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;
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");
+ }
}
}
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. */
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;
+ }
+ }
}
}
}
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;
}
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:
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;
}
\f
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
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
@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.
+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
/* 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.
/* 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
{
+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.
--- /dev/null
+/* 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) ();
+}
--- /dev/null
+/* Test boolean conversion as part of returning unsigned value does
+ not lead to an ICE. */
+
+_Bool f(unsigned a) { return a & 1; }
--- /dev/null
+/* Test boolean conversion of an overflowing integer return value does
+ not lead to an ICE. */
+
+_Bool f(void) { return __INT_MAX__ + 1; }
--- /dev/null
+/* 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())
+};
--- /dev/null
+/* 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())
+};
--- /dev/null
+/* 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" } */
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" } */
}
--- /dev/null
+/* 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" } */
+}
--- /dev/null
+/* 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" } */
+}
{
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" } */
}
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" } */
}
--- /dev/null
+/* 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" } */
+ ;
+ }
+}
--- /dev/null
+/* 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 } */
--- /dev/null
+/* 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. */
+};
--- /dev/null
+/* 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])
+};
--- /dev/null
+/* 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" } */
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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" } */
+}
--- /dev/null
+/* 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)];
+}
{
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)));
}
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" } */
}
--- /dev/null
+/* 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" } */
+ ;
+ }
+}
--- /dev/null
+/* 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 } */
--- /dev/null
+/* 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. */
+};
--- /dev/null
+/* 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])
+};
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). */
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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" } */
+}
--- /dev/null
+/* 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 } */
+}
--- /dev/null
+/* 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; }));
+}
--- /dev/null
+/* 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 } */
+}
--- /dev/null
+/* 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;
+}
/* 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" } */
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" } */
};
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
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" } */
;
/* 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" } */
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" } */
};
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
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" } */
;
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);
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;
}
/* 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. */
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
/* 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
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 } */
;
}
}
/* 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. */
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
/* 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
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 } */
;
}
}
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);
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 ("");
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 *);
/* PR middle-end/21781. */
/* { dg-do compile } */
+/* { dg-options "-Wall" } */
-int f[.0e200000000 == 0?1:-1];
+int foo(void) { if (.0e200000000 == 0 ) return 1; }
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" } } */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}