re PR c/456 (constant expressions constraints (gcc.dg/c90-const-expr-1))

PR c/456
	PR c/5675
	PR c/19976
	PR c/29116
	PR c/31871
	PR c/35198

fixincludes:
	* inclhack.def (glibc_tgmath): New fix.
	* fixincl.x: Regenerate.
	* tests/base/tgmath.h: New.

gcc:
	* builtins.c (fold_builtin_sincos): Build COMPOUND_EXPR in
	void_type_node.
	(fold_call_expr): Return a NOP_EXPR from folding rather than the
	contained expression.
	* c-common.c (c_fully_fold, c_fully_fold_internal, c_save_expr):
	New.
	(c_common_truthvalue_conversion): Use c_save_expr.  Do not fold
	conditional expressions for C.
	(decl_constant_value_for_optimization): Move from
	decl_constant_value_for_broken_optimization in c-typeck.c.  Check
	whether optimizing and that the expression is a VAR_DECL not of
	array type instead of doing such checks in the caller.  Do not
	check pedantic.  Call gcc_unreachable for C++.
	* c-common.def (C_MAYBE_CONST_EXPR): New.
	* c-common.h (c_fully_fold, c_save_expr,
	decl_constant_value_for_optimization): New prototypes.
	(C_MAYBE_CONST_EXPR_PRE, C_MAYBE_CONST_EXPR_EXPR,
	C_MAYBE_CONST_EXPR_INT_OPERANDS, C_MAYBE_CONST_EXPR_NON_CONST,
	EXPR_INT_CONST_OPERANDS): Define.
	* c-convert.c (convert): Strip nops from expression.
	* c-decl.c (groktypename): Take extra parameters expr and
	expr_const_operands.  Update call to grokdeclarator.
	(start_decl): Update call to grokdeclarator.  Add statement for
	expressions used in type of decl.
	(grokparm): Update call to grokdeclarator.
	(push_parm_decl): Update call to grokdeclarator.
	(build_compound_literal): Add parameter non_const and build a
	C_MAYBE_COSNT_EXPR if applicable.
	(grokdeclarator): Take extra parameters expr and
	expr_const_operands.  Track expressions used in declaration
	specifiers and declarators.  Fold array sizes and track whether
	they are constant expressions and whether they are integer
	constant expressions.
	(parser_xref_tag): Set expr and expr_const_operands fields in
	return value.
	(grokfield): Update call to grokdeclarator.
	(start_function): Update call to grokdeclarator.
	(build_null_declspecs): Set expr and expr_const_operands fields in
	return value.
	(declspecs_add_type): Handle expressions in typeof specifiers.
	* c-parser.c (c_parser_declspecs): Set expr and
	expr_const_operands fields for declaration specifiers.
	(c_parser_enum_specifier): Likewise.
	(c_parser_struct_or_union_specifier): Likewise.
	(c_parser_typeof_specifier): Likewise.  Update call to
	groktypename.  Fold expression as needed.  Return expressions with
	type instead of adding statements.
	(c_parser_attributes): Update calls to c_parser_expr_list.
	(c_parser_statement_after_labels): Fold expression before passing
	to objc_build_throw_stmt.
	(c_parser_condition): Fold expression.
	(c_parser_asm_operands): Fold expression.
	(c_parser_conditional_expression): Use c_save_expr.  Update call
	to build_conditional_expr.
	(c_parser_alignof_expression): Update call to groktypename.
	(c_parser_postfix_expression): Preserve C_MAYBE_CONST_EXPR as
	original_code.  Fold expression argument of va_arg.  Create
	C_MAYBE_CONST_EXPR to preserve side effects of expressions in type
	argument to va_arg.  Update calls to groktypename.  Fold array
	index for offsetof.  Verify that first argument to
	__builtin_choose_expr has integer type.
	(c_parser_postfix_expression_after_paren_type): Update calls to
	groktypename and build_compound_literal.  Handle expressions with
	side effects in type name.
	(c_parser_postfix_expression_after_primary): Update call to
	c_parser_expr_list.  Set original_code for calls to
	__builtin_constant_p.
	(c_parser_expr_list): Take extra parameter fold_p.  Fold
	expressions if requested.
	(c_parser_objc_type_name): Update call to groktypename.
	(c_parser_objc_synchronized_statement): Fold expression.
	(c_parser_objc_receiver): Fold expression.
	(c_parser_objc_keywordexpr): Update call to c_parser_expr_list.
	(c_parser_omp_clause_num_threads, c_parser_omp_clause_schedule,
	c_parser_omp_atomic, c_parser_omp_for_loop): Fold expressions.
	* c-tree.h (CONSTRUCTOR_NON_CONST): Define.
	(struct c_typespec): Add elements expr and expr_const_operands.
	(struct c_declspecs): Add elements expr and expr_const_operands.
	(groktypename, build_conditional_expr, build_compound_literal):
	Update prototypes.
	(in_late_binary_op): Declare.
	* c-typeck.c (note_integer_operands): New function.
	(in_late_binary_op): New variable.
	(decl_constant_value_for_broken_optimization): Move to c-common.c
	and rename to decl_constant_value_for_optimization.
	(default_function_array_conversion): Do not strip nops.
	(default_conversion): Do not call
	decl_constant_value_for_broken_optimization.
	(build_array_ref): Do not fold result.
	(c_expr_sizeof_expr): Fold operand.  Use C_MAYBE_CONST_EXPR for
	result when operand is a VLA.
	(c_expr_sizeof_type): Update call to groktypename.  Handle
	expressions included in type name.  Use C_MAYBE_CONST_EXPR for
	result when operand names a VLA type.
	(build_function_call): Update call to build_compound_literal.
	Only fold result for calls to __builtin_* functions.  Strip
	NOP_EXPR from INTEGER_CST returned from such functions.  Fold
	the function designator.
	(convert_arguments): Fold arguments.  Update call to
	convert_for_assignment.
	(build_unary_op): Handle increment and decrement of
	C_MAYBE_CONST_EXPR.  Move lvalue checks for increment and
	decrement earlier.  Fold operand of increment and decrement.
	Handle address of C_MAYBE_CONST_EXPR.  Only fold expression being
	built for integer operand.  Wrap returns that are INTEGER_CSTs
	without being integer constant expressions or that have integer
	constant operands without being INTEGER_CSTs.
	(lvalue_p): Handle C_MAYBE_CONST_EXPR.
	(build_conditional_expr): Add operand ifexp_bcp.  Track whether
	result is an integer constant expression or can be used in
	unevaluated parts of one and avoid folding and wrap as
	appropriate.  Fold operands before possibly doing -Wsign-compare
	warnings.
	(build_compound_expr): Wrap result for C99 if operands can be used
	in integer constant expressions.
	(build_c_cast): Update call to digest_init.  Do not ignore
	overflow from casting floating-point constants to integers.  Wrap
	results that could be confused with integer constant expressions,
	null pointer constants or floating-point constants.
	(c_cast_expr): Update call to groktypename.  Handle expressions
	included in type name.
	(build_modify_expr): Handle modifying a C_MAYBE_CONST_EXPR.  Fold
	lhs inside possible SAVE_EXPR.  Fold RHS before assignment.
	Update calls to convert_for_assignment.
	(convert_for_assignment): Take new parameter
	null_pointer_constant.  Do not strip nops or call
	decl_constant_value_for_broken_optimization.  Set
	in_late_binary_op for conversions to boolean.
	(store_init_value): Update call to digest_init.
	(digest_init): Take new parameter null_pointer_constant.  Do not
	call decl_constant_value_for_broken_optimization.  pedwarn for
	initializers not constant expressions.  Update calls to
	convert_for_assignment.
	(constructor_nonconst): New.
	(struct constructor_stack): Add nonconst element.
	(really_start_incremental_init, push_init_level, pop_init_level):
	Handle constructor_nonconst and nonconst element.
	(set_init_index): Call constant_expression_warning for array
	designators.
	(output_init_element): Fold value.  Set constructor_nonconst as
	applicable.  pedwarn for initializers not constant expressions.
	Update call to digest_init.  Call constant_expression_warning
	where constant initializers are required.
	(process_init_element): Use c_save_expr.
	(c_finish_goto_ptr): Fold expression.
	(c_finish_return): Fold return value.  Update call to
	convert_for_assignment.
	(c_start_case): Fold switch expression.
	(c_process_expr_stmt): Fold expression.
	(c_finish_stmt_expr): Create C_MAYBE_CONST_EXPR as needed to
	ensure statement expression is not evaluated in constant
	expression.
	(build_binary_op): Track whether results are integer constant
	expressions or may occur in such, disable folding and wrap results
	as applicable.  Fold operands for -Wsign-compare warnings unless
	in_late_binary_op.
	(c_objc_common_truthvalue_conversion): Handle results folded to
	integer constants that are not integer constant expressions.
	* doc/extend.texi: Document when typeof operands are evaluated,
	that condition of __builtin_choose_expr is an integer constant
	expression, and more about use of __builtin_constant_p in
	initializers.

gcc/objc:
	* objc-act.c (objc_finish_try_stmt): Set in_late_binary_op.

gcc/testsuite:
	* gcc.c-torture/compile/20081108-1.c,
	gcc.c-torture/compile/20081108-2.c,
	gcc.c-torture/compile/20081108-3.c, gcc.dg/bconstp-2.c,
	gcc.dg/bconstp-3.c, gcc.dg/bconstp-4.c, gcc.dg/c90-const-expr-6.c,
	gcc.dg/c90-const-expr-7.c, gcc.dg/c90-const-expr-8.c,
	gcc.dg/c90-const-expr-9.c, gcc.dg/c90-const-expr-10.c,
	gcc.dg/c90-const-expr-11.c, gcc.dg/c99-const-expr-6.c,
	gcc.dg/c99-const-expr-7.c, gcc.dg/c99-const-expr-8.c,
	gcc.dg/c99-const-expr-9.c, gcc.dg/c99-const-expr-10.c,
	gcc.dg/c99-const-expr-11.c, gcc.dg/c99-const-expr-12.c,
	gcc.dg/c99-const-expr-13.c, gcc.dg/compare10.c,
	gcc.dg/gnu89-const-expr-1.c, gcc.dg/gnu89-const-expr-2.c,
	gcc.dg/gnu99-const-expr-1.c, gcc.dg/gnu99-const-expr-2.c,
	gcc.dg/gnu99-const-expr-3.c, gcc.dg/vla-12.c, gcc.dg/vla-13.c,
	gcc.dg/vla-14.c, gcc.dg/vla-15.c, gcc.dg/vla-16.c: New tests.
	* gcc.dg/c90-const-expr-1.c, gcc.dg/c90-const-expr-2.c,
	gcc.dg/c90-const-expr-3.c, gcc.dg/c99-const-expr-2.c,
	gcc.dg/c99-const-expr-3.c, gcc.dg/c99-static-1.c: Remove XFAILs.
	* gcc.dg/c90-const-expr-2.c: Use ZERO in place of 0 in another
	case.
	* gcc.dg/overflow-warn-1.c, gcc.dg/overflow-warn-2.c,
	gcc.dg/overflow-warn-3.c, gcc.dg/overflow-warn-4.c: Remove
	XFAILs.  Update expected messages.
	* gcc.dg/pr14649-1.c, gcc.dg/pr19984.c, gcc.dg/pr25682.c: Update
	expected messages.
	* gcc.dg/real-const-1.c: Replace with test from original PR.
	* gcc.dg/vect/pr32230.c: Use intermediate cast to __PTRDIFF_TYPE__
	when casting from non-constant integer to pointer.

From-SVN: r145254
This commit is contained in:
Joseph Myers 2009-03-29 19:13:43 +01:00 committed by Joseph Myers
parent 5babbcc0fc
commit 928c19bbb0
64 changed files with 2630 additions and 289 deletions

View File

@ -1,3 +1,15 @@
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,

View File

@ -2,11 +2,11 @@
*
* 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.
*
@ -15,7 +15,7 @@
* 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.
*
@ -2217,6 +2217,49 @@ s/{ { 0, } }/{ { 0, 0, 0, 0, 0, 0 } }/\n\
"-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
@ -7192,9 +7235,9 @@ static const char* apzX11_SprintfPatch[] = {
*
* 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
@ -7253,6 +7296,7 @@ typedef enum {
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,
@ -7645,6 +7689,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
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,

View File

@ -1265,6 +1265,19 @@ fix = {
};
/* 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.

View File

@ -0,0 +1,14 @@
/* 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 */

View File

@ -1,3 +1,174 @@
2009-03-29 Joseph Myers <joseph@codesourcery.com>
PR c/456
PR c/5675
PR c/19976
PR c/29116
PR c/31871
PR c/35198
* builtins.c (fold_builtin_sincos): Build COMPOUND_EXPR in
void_type_node.
(fold_call_expr): Return a NOP_EXPR from folding rather than the
contained expression.
* c-common.c (c_fully_fold, c_fully_fold_internal, c_save_expr):
New.
(c_common_truthvalue_conversion): Use c_save_expr. Do not fold
conditional expressions for C.
(decl_constant_value_for_optimization): Move from
decl_constant_value_for_broken_optimization in c-typeck.c. Check
whether optimizing and that the expression is a VAR_DECL not of
array type instead of doing such checks in the caller. Do not
check pedantic. Call gcc_unreachable for C++.
* c-common.def (C_MAYBE_CONST_EXPR): New.
* c-common.h (c_fully_fold, c_save_expr,
decl_constant_value_for_optimization): New prototypes.
(C_MAYBE_CONST_EXPR_PRE, C_MAYBE_CONST_EXPR_EXPR,
C_MAYBE_CONST_EXPR_INT_OPERANDS, C_MAYBE_CONST_EXPR_NON_CONST,
EXPR_INT_CONST_OPERANDS): Define.
* c-convert.c (convert): Strip nops from expression.
* c-decl.c (groktypename): Take extra parameters expr and
expr_const_operands. Update call to grokdeclarator.
(start_decl): Update call to grokdeclarator. Add statement for
expressions used in type of decl.
(grokparm): Update call to grokdeclarator.
(push_parm_decl): Update call to grokdeclarator.
(build_compound_literal): Add parameter non_const and build a
C_MAYBE_COSNT_EXPR if applicable.
(grokdeclarator): Take extra parameters expr and
expr_const_operands. Track expressions used in declaration
specifiers and declarators. Fold array sizes and track whether
they are constant expressions and whether they are integer
constant expressions.
(parser_xref_tag): Set expr and expr_const_operands fields in
return value.
(grokfield): Update call to grokdeclarator.
(start_function): Update call to grokdeclarator.
(build_null_declspecs): Set expr and expr_const_operands fields in
return value.
(declspecs_add_type): Handle expressions in typeof specifiers.
* c-parser.c (c_parser_declspecs): Set expr and
expr_const_operands fields for declaration specifiers.
(c_parser_enum_specifier): Likewise.
(c_parser_struct_or_union_specifier): Likewise.
(c_parser_typeof_specifier): Likewise. Update call to
groktypename. Fold expression as needed. Return expressions with
type instead of adding statements.
(c_parser_attributes): Update calls to c_parser_expr_list.
(c_parser_statement_after_labels): Fold expression before passing
to objc_build_throw_stmt.
(c_parser_condition): Fold expression.
(c_parser_asm_operands): Fold expression.
(c_parser_conditional_expression): Use c_save_expr. Update call
to build_conditional_expr.
(c_parser_alignof_expression): Update call to groktypename.
(c_parser_postfix_expression): Preserve C_MAYBE_CONST_EXPR as
original_code. Fold expression argument of va_arg. Create
C_MAYBE_CONST_EXPR to preserve side effects of expressions in type
argument to va_arg. Update calls to groktypename. Fold array
index for offsetof. Verify that first argument to
__builtin_choose_expr has integer type.
(c_parser_postfix_expression_after_paren_type): Update calls to
groktypename and build_compound_literal. Handle expressions with
side effects in type name.
(c_parser_postfix_expression_after_primary): Update call to
c_parser_expr_list. Set original_code for calls to
__builtin_constant_p.
(c_parser_expr_list): Take extra parameter fold_p. Fold
expressions if requested.
(c_parser_objc_type_name): Update call to groktypename.
(c_parser_objc_synchronized_statement): Fold expression.
(c_parser_objc_receiver): Fold expression.
(c_parser_objc_keywordexpr): Update call to c_parser_expr_list.
(c_parser_omp_clause_num_threads, c_parser_omp_clause_schedule,
c_parser_omp_atomic, c_parser_omp_for_loop): Fold expressions.
* c-tree.h (CONSTRUCTOR_NON_CONST): Define.
(struct c_typespec): Add elements expr and expr_const_operands.
(struct c_declspecs): Add elements expr and expr_const_operands.
(groktypename, build_conditional_expr, build_compound_literal):
Update prototypes.
(in_late_binary_op): Declare.
* c-typeck.c (note_integer_operands): New function.
(in_late_binary_op): New variable.
(decl_constant_value_for_broken_optimization): Move to c-common.c
and rename to decl_constant_value_for_optimization.
(default_function_array_conversion): Do not strip nops.
(default_conversion): Do not call
decl_constant_value_for_broken_optimization.
(build_array_ref): Do not fold result.
(c_expr_sizeof_expr): Fold operand. Use C_MAYBE_CONST_EXPR for
result when operand is a VLA.
(c_expr_sizeof_type): Update call to groktypename. Handle
expressions included in type name. Use C_MAYBE_CONST_EXPR for
result when operand names a VLA type.
(build_function_call): Update call to build_compound_literal.
Only fold result for calls to __builtin_* functions. Strip
NOP_EXPR from INTEGER_CST returned from such functions. Fold
the function designator.
(convert_arguments): Fold arguments. Update call to
convert_for_assignment.
(build_unary_op): Handle increment and decrement of
C_MAYBE_CONST_EXPR. Move lvalue checks for increment and
decrement earlier. Fold operand of increment and decrement.
Handle address of C_MAYBE_CONST_EXPR. Only fold expression being
built for integer operand. Wrap returns that are INTEGER_CSTs
without being integer constant expressions or that have integer
constant operands without being INTEGER_CSTs.
(lvalue_p): Handle C_MAYBE_CONST_EXPR.
(build_conditional_expr): Add operand ifexp_bcp. Track whether
result is an integer constant expression or can be used in
unevaluated parts of one and avoid folding and wrap as
appropriate. Fold operands before possibly doing -Wsign-compare
warnings.
(build_compound_expr): Wrap result for C99 if operands can be used
in integer constant expressions.
(build_c_cast): Update call to digest_init. Do not ignore
overflow from casting floating-point constants to integers. Wrap
results that could be confused with integer constant expressions,
null pointer constants or floating-point constants.
(c_cast_expr): Update call to groktypename. Handle expressions
included in type name.
(build_modify_expr): Handle modifying a C_MAYBE_CONST_EXPR. Fold
lhs inside possible SAVE_EXPR. Fold RHS before assignment.
Update calls to convert_for_assignment.
(convert_for_assignment): Take new parameter
null_pointer_constant. Do not strip nops or call
decl_constant_value_for_broken_optimization. Set
in_late_binary_op for conversions to boolean.
(store_init_value): Update call to digest_init.
(digest_init): Take new parameter null_pointer_constant. Do not
call decl_constant_value_for_broken_optimization. pedwarn for
initializers not constant expressions. Update calls to
convert_for_assignment.
(constructor_nonconst): New.
(struct constructor_stack): Add nonconst element.
(really_start_incremental_init, push_init_level, pop_init_level):
Handle constructor_nonconst and nonconst element.
(set_init_index): Call constant_expression_warning for array
designators.
(output_init_element): Fold value. Set constructor_nonconst as
applicable. pedwarn for initializers not constant expressions.
Update call to digest_init. Call constant_expression_warning
where constant initializers are required.
(process_init_element): Use c_save_expr.
(c_finish_goto_ptr): Fold expression.
(c_finish_return): Fold return value. Update call to
convert_for_assignment.
(c_start_case): Fold switch expression.
(c_process_expr_stmt): Fold expression.
(c_finish_stmt_expr): Create C_MAYBE_CONST_EXPR as needed to
ensure statement expression is not evaluated in constant
expression.
(build_binary_op): Track whether results are integer constant
expressions or may occur in such, disable folding and wrap results
as applicable. Fold operands for -Wsign-compare warnings unless
in_late_binary_op.
(c_objc_common_truthvalue_conversion): Handle results folded to
integer constants that are not integer constant expressions.
* doc/extend.texi: Document when typeof operands are evaluated,
that condition of __builtin_choose_expr is an integer constant
expression, and more about use of __builtin_constant_p in
initializers.
2009-03-29 Richard Guenther <rguenther@suse.de>
* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Properly

View File

@ -7930,7 +7930,7 @@ fold_builtin_sincos (tree arg0, tree arg1, tree arg2)
call = build_call_expr (fn, 1, arg0);
call = builtin_save_expr (call);
return build2 (COMPOUND_EXPR, type,
return build2 (COMPOUND_EXPR, void_type_node,
build2 (MODIFY_EXPR, void_type_node,
build_fold_indirect_ref (arg1),
build1 (IMAGPART_EXPR, type, call)),
@ -10929,7 +10929,6 @@ fold_call_expr (tree exp, bool ignore)
if (CAN_HAVE_LOCATION_P (realret)
&& !EXPR_HAS_LOCATION (realret))
SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
return realret;
}
return ret;
}

View File

@ -518,6 +518,7 @@ const struct fname_var_t fname_vars[] =
{NULL, 0, 0},
};
static tree c_fully_fold_internal (tree expr, bool, bool *, bool *);
static tree check_case_value (tree);
static bool check_case_bounds (tree, tree, tree *, tree *);
@ -1107,6 +1108,390 @@ fix_string_type (tree value)
return value;
}
/* Fully fold EXPR, an expression that was not folded (beyond integer
constant expressions and null pointer constants) when being built
up. If IN_INIT, this is in a static initializer and certain
changes are made to the folding done. Clear *MAYBE_CONST if
MAYBE_CONST is not NULL and EXPR is definitely not a constant
expression because it contains an evaluated operator (in C99) or an
operator outside of sizeof returning an integer constant (in C90)
not permitted in constant expressions, or because it contains an
evaluated arithmetic overflow. (*MAYBE_CONST should typically be
set to true by callers before calling this function.) Return the
folded expression. Function arguments have already been folded
before calling this function, as have the contents of SAVE_EXPR,
TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and
C_MAYBE_CONST_EXPR. */
tree
c_fully_fold (tree expr, bool in_init, bool *maybe_const)
{
tree ret;
bool dummy = true;
bool maybe_const_itself = true;
/* This function is not relevant to C++ because C++ folds while
parsing, and may need changes to be correct for C++ when C++
stops folding while parsing. */
if (c_dialect_cxx ())
gcc_unreachable ();
if (!maybe_const)
maybe_const = &dummy;
ret = c_fully_fold_internal (expr, in_init, maybe_const,
&maybe_const_itself);
*maybe_const &= maybe_const_itself;
return ret;
}
/* Internal helper for c_fully_fold. EXPR and IN_INIT are as for
c_fully_fold. *MAYBE_CONST_OPERANDS is cleared because of operands
not permitted, while *MAYBE_CONST_ITSELF is cleared because of
arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from
both evaluated and unevaluated subexpressions while
*MAYBE_CONST_ITSELF is carried from only evaluated
subexpressions). */
static tree
c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
bool *maybe_const_itself)
{
tree ret = expr;
enum tree_code code = TREE_CODE (expr);
enum tree_code_class kind = TREE_CODE_CLASS (code);
location_t loc = EXPR_LOCATION (expr);
tree op0, op1, op2, op3;
tree orig_op0, orig_op1, orig_op2;
bool op0_const = true, op1_const = true, op2_const = true;
bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
bool nowarning = TREE_NO_WARNING (expr);
/* This function is not relevant to C++ because C++ folds while
parsing, and may need changes to be correct for C++ when C++
stops folding while parsing. */
if (c_dialect_cxx ())
gcc_unreachable ();
/* Constants, declarations, statements, errors, SAVE_EXPRs and
anything else not counted as an expression cannot usefully be
folded further at this point. */
if (!IS_EXPR_CODE_CLASS (kind)
|| kind == tcc_statement
|| code == SAVE_EXPR)
return expr;
/* Operands of variable-length expressions (function calls) have
already been folded, as have __builtin_* function calls, and such
expressions cannot occur in constant expressions. */
if (kind == tcc_vl_exp)
{
*maybe_const_operands = false;
ret = fold (expr);
goto out;
}
if (code == C_MAYBE_CONST_EXPR)
{
tree pre = C_MAYBE_CONST_EXPR_PRE (expr);
tree inner = C_MAYBE_CONST_EXPR_EXPR (expr);
if (C_MAYBE_CONST_EXPR_NON_CONST (expr))
*maybe_const_operands = false;
if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr))
*maybe_const_itself = false;
if (pre && !in_init)
ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner);
else
ret = inner;
goto out;
}
/* Assignment, increment, decrement, function call and comma
operators, and statement expressions, cannot occur in constant
expressions if evaluated / outside of sizeof. (Function calls
were handled above, though VA_ARG_EXPR is treated like a function
call here, and statement expressions are handled through
C_MAYBE_CONST_EXPR to avoid folding inside them.) */
switch (code)
{
case MODIFY_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
case COMPOUND_EXPR:
*maybe_const_operands = false;
break;
case VA_ARG_EXPR:
case TARGET_EXPR:
case BIND_EXPR:
case OBJ_TYPE_REF:
*maybe_const_operands = false;
ret = fold (expr);
goto out;
default:
break;
}
/* Fold individual tree codes as appropriate. */
switch (code)
{
case COMPOUND_LITERAL_EXPR:
/* Any non-constancy will have been marked in a containing
C_MAYBE_CONST_EXPR; there is no more folding to do here. */
goto out;
case COMPONENT_REF:
orig_op0 = op0 = TREE_OPERAND (expr, 0);
op1 = TREE_OPERAND (expr, 1);
op2 = TREE_OPERAND (expr, 2);
op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
maybe_const_itself);
if (op0 != orig_op0)
ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
if (ret != expr)
{
TREE_READONLY (ret) = TREE_READONLY (expr);
TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
}
goto out;
case ARRAY_REF:
orig_op0 = op0 = TREE_OPERAND (expr, 0);
orig_op1 = op1 = TREE_OPERAND (expr, 1);
op2 = TREE_OPERAND (expr, 2);
op3 = TREE_OPERAND (expr, 3);
op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
maybe_const_itself);
op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
maybe_const_itself);
op1 = decl_constant_value_for_optimization (op1);
if (op0 != orig_op0 || op1 != orig_op1)
ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3);
if (ret != expr)
{
TREE_READONLY (ret) = TREE_READONLY (expr);
TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
}
ret = fold (ret);
goto out;
case COMPOUND_EXPR:
case MODIFY_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case POINTER_PLUS_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case TRUNC_MOD_EXPR:
case RDIV_EXPR:
case EXACT_DIV_EXPR:
case LSHIFT_EXPR:
case RSHIFT_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_AND_EXPR:
case LT_EXPR:
case LE_EXPR:
case GT_EXPR:
case GE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case COMPLEX_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
/* Binary operations evaluating both arguments (increment and
decrement are binary internally in GCC). */
orig_op0 = op0 = TREE_OPERAND (expr, 0);
orig_op1 = op1 = TREE_OPERAND (expr, 1);
op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
maybe_const_itself);
if (code != MODIFY_EXPR
&& code != PREDECREMENT_EXPR
&& code != PREINCREMENT_EXPR
&& code != POSTDECREMENT_EXPR
&& code != POSTINCREMENT_EXPR)
op0 = decl_constant_value_for_optimization (op0);
/* The RHS of a MODIFY_EXPR was fully folded when building that
expression for the sake of conversion warnings. */
if (code != MODIFY_EXPR)
op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
maybe_const_itself);
op1 = decl_constant_value_for_optimization (op1);
if (op0 != orig_op0 || op1 != orig_op1 || in_init)
ret = in_init
? fold_build2_initializer (code, TREE_TYPE (expr), op0, op1)
: fold_build2 (code, TREE_TYPE (expr), op0, op1);
else
ret = fold (expr);
goto out;
case INDIRECT_REF:
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
CASE_CONVERT:
case NON_LVALUE_EXPR:
case NEGATE_EXPR:
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case ADDR_EXPR:
case CONJ_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
/* Unary operations. */
orig_op0 = op0 = TREE_OPERAND (expr, 0);
op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
maybe_const_itself);
if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
op0 = decl_constant_value_for_optimization (op0);
if (op0 != orig_op0 || in_init)
ret = in_init
? fold_build1_initializer (code, TREE_TYPE (expr), op0)
: fold_build1 (code, TREE_TYPE (expr), op0);
else
ret = fold (expr);
if (code == INDIRECT_REF
&& ret != expr
&& TREE_CODE (ret) == INDIRECT_REF)
{
TREE_READONLY (ret) = TREE_READONLY (expr);
TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
}
goto out;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
/* Binary operations not necessarily evaluating both
arguments. */
orig_op0 = op0 = TREE_OPERAND (expr, 0);
orig_op1 = op1 = TREE_OPERAND (expr, 1);
op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
if (op0 != orig_op0 || op1 != orig_op1 || in_init)
ret = in_init
? fold_build2_initializer (code, TREE_TYPE (expr), op0, op1)
: fold_build2 (code, TREE_TYPE (expr), op0, op1);
else
ret = fold (expr);
*maybe_const_operands &= op0_const;
*maybe_const_itself &= op0_const_self;
if (!(flag_isoc99
&& op0_const
&& op0_const_self
&& (code == TRUTH_ANDIF_EXPR
? op0 == truthvalue_false_node
: op0 == truthvalue_true_node)))
*maybe_const_operands &= op1_const;
if (!(op0_const
&& op0_const_self
&& (code == TRUTH_ANDIF_EXPR
? op0 == truthvalue_false_node
: op0 == truthvalue_true_node)))
*maybe_const_itself &= op1_const_self;
goto out;
case COND_EXPR:
orig_op0 = op0 = TREE_OPERAND (expr, 0);
orig_op1 = op1 = TREE_OPERAND (expr, 1);
orig_op2 = op2 = TREE_OPERAND (expr, 2);
op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
ret = fold_build3 (code, TREE_TYPE (expr), op0, op1, op2);
else
ret = fold (expr);
*maybe_const_operands &= op0_const;
*maybe_const_itself &= op0_const_self;
if (!(flag_isoc99
&& op0_const
&& op0_const_self
&& op0 == truthvalue_false_node))
*maybe_const_operands &= op1_const;
if (!(op0_const
&& op0_const_self
&& op0 == truthvalue_false_node))
*maybe_const_itself &= op1_const_self;
if (!(flag_isoc99
&& op0_const
&& op0_const_self
&& op0 == truthvalue_true_node))
*maybe_const_operands &= op2_const;
if (!(op0_const
&& op0_const_self
&& op0 == truthvalue_true_node))
*maybe_const_itself &= op2_const_self;
goto out;
default:
/* Various codes may appear through folding built-in functions
and their arguments. */
goto out;
}
out:
/* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks
have been done by this point, so remove them again. */
nowarning |= TREE_NO_WARNING (ret);
STRIP_TYPE_NOPS (ret);
if (nowarning && !TREE_NO_WARNING (ret))
{
if (!CAN_HAVE_LOCATION_P (ret))
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
TREE_NO_WARNING (ret) = 1;
}
if (ret != expr)
protected_set_expr_location (ret, loc);
return ret;
}
/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type,
return EXP. Otherwise, return either EXP or its known constant
value (if it has one), but return EXP if EXP has mode BLKmode. ???
Is the BLKmode test appropriate? */
tree
decl_constant_value_for_optimization (tree exp)
{
tree ret;
/* This function is only used by C, for c_fully_fold and other
optimization, and may not be correct for C++. */
if (c_dialect_cxx ())
gcc_unreachable ();
if (!optimize
|| TREE_CODE (exp) != VAR_DECL
|| TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
|| DECL_MODE (exp) == BLKmode)
return exp;
ret = decl_constant_value (exp);
/* Avoid unwanted tree sharing between the initializer and current
function's body where the tree can be modified e.g. by the
gimplifier. */
if (ret != exp && TREE_STATIC (exp))
ret = unshare_expr (ret);
return ret;
}
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
requires to be a constant expression.
@ -3328,6 +3713,27 @@ pointer_int_sum (location_t location, enum tree_code resultcode,
return ret;
}
/* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but
for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
around the SAVE_EXPR if needed so that c_fully_fold does not need
to look inside SAVE_EXPRs. */
tree
c_save_expr (tree expr)
{
bool maybe_const = true;
if (c_dialect_cxx ())
return save_expr (expr);
expr = c_fully_fold (expr, false, &maybe_const);
expr = save_expr (expr);
if (!maybe_const)
{
expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr);
C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1;
}
return expr;
}
/* Return whether EXPR is a declaration whose address can never be
NULL. */
@ -3470,7 +3876,18 @@ c_common_truthvalue_conversion (location_t location, tree expr)
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
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)),
@ -3506,7 +3923,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
{
tree t = save_expr (expr);
tree t = c_save_expr (expr);
return (build_binary_op
(EXPR_LOCATION (expr),
(TREE_SIDE_EFFECTS (expr)

View File

@ -2,7 +2,7 @@
additional tree codes used in the GNU C compiler (see tree.def
for the standard codes).
Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998,
1999, 2000, 2001, 2004, 2005, 2007 Free Software Foundation, Inc.
1999, 2000, 2001, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
Written by Benjamin Chelf <chelf@codesourcery.com>
This file is part of GCC.
@ -31,6 +31,21 @@ along with GCC; see the file COPYING3. If not see
the compound literal. */
DEFTREECODE (COMPOUND_LITERAL_EXPR, "compound_literal_expr", tcc_expression, 1)
/* A C_MAYBE_CONST_EXPR, currently only used for C and Objective C,
tracks information about constancy of an expression and VLA type
sizes or VM expressions from typeof that need to be evaluated
before the main expression. It is used during parsing and removed
in c_fully_fold. C_MAYBE_CONST_EXPR_PRE is the expression to
evaluate first, if not NULL; C_MAYBE_CONST_EXPR_EXPR is the main
expression. If C_MAYBE_CONST_EXPR_INT_OPERANDS is set then the
expression may be used in an unevaluated part of an integer
constant expression, but not in an evaluated part. If
C_MAYBE_CONST_EXPR_NON_CONST is set then the expression contains
something that cannot occur in an evaluated part of a constant
expression (or outside of sizeof in C90 mode); otherwise it does
not. */
DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2)
/*
Local variables:
mode:c

View File

@ -1,6 +1,6 @@
/* Definitions for c-common.c.
Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
@ -30,8 +30,10 @@ along with GCC; see the file COPYING3. If not see
0: TREE_NEGATED_INT (in INTEGER_CST).
IDENTIFIER_MARKED (used by search routines).
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
C_MAYBE_CONST_EXPR_INT_OPERANDS (in C_MAYBE_CONST_EXPR, for C)
1: C_DECLARED_LABEL_FLAG (in LABEL_DECL)
STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST)
C_MAYBE_CONST_EXPR_NON_CONST (in C_MAYBE_CONST_EXPR, for C)
2: unused
3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST)
4: unused
@ -715,6 +717,9 @@ extern tree c_common_signed_type (tree);
extern tree c_common_signed_or_unsigned_type (int, tree);
extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
extern bool decl_with_nonnull_addr_p (const_tree);
extern tree c_fully_fold (tree, bool, bool *);
extern tree decl_constant_value_for_optimization (tree);
extern tree c_save_expr (tree);
extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (tree, bool, int);
@ -799,6 +804,21 @@ extern void finish_file (void);
#define COMPOUND_LITERAL_EXPR_DECL(NODE) \
DECL_EXPR_DECL (COMPOUND_LITERAL_EXPR_DECL_STMT (NODE))
/* C_MAYBE_CONST_EXPR accessors. */
#define C_MAYBE_CONST_EXPR_PRE(NODE) \
TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 0)
#define C_MAYBE_CONST_EXPR_EXPR(NODE) \
TREE_OPERAND (C_MAYBE_CONST_EXPR_CHECK (NODE), 1)
#define C_MAYBE_CONST_EXPR_INT_OPERANDS(NODE) \
TREE_LANG_FLAG_0 (C_MAYBE_CONST_EXPR_CHECK (NODE))
#define C_MAYBE_CONST_EXPR_NON_CONST(NODE) \
TREE_LANG_FLAG_1 (C_MAYBE_CONST_EXPR_CHECK (NODE))
#define EXPR_INT_CONST_OPERANDS(EXPR) \
(INTEGRAL_TYPE_P (TREE_TYPE (EXPR)) \
&& (TREE_CODE (EXPR) == INTEGER_CST \
|| (TREE_CODE (EXPR) == C_MAYBE_CONST_EXPR \
&& C_MAYBE_CONST_EXPR_INT_OPERANDS (EXPR))))
/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */
#define DECL_C_BIT_FIELD(NODE) \
(DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)

View File

@ -1,6 +1,6 @@
/* Language-level data type conversion for GNU C.
Copyright (C) 1987, 1988, 1991, 1998, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
Copyright (C) 1987, 1988, 1991, 1998, 2002, 2003, 2004, 2005, 2007, 2008,
2009 Free Software Foundation, Inc.
This file is part of GCC.
@ -86,6 +86,8 @@ convert (tree type, tree expr)
if (type == TREE_TYPE (expr))
return expr;
STRIP_TYPE_NOPS (e);
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
return fold_convert (type, expr);
if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)

View File

@ -410,8 +410,8 @@ static tree lookup_name_in_scope (tree, struct c_scope *);
static tree c_make_fname_decl (tree, int);
static tree grokdeclarator (const struct c_declarator *,
struct c_declspecs *,
enum decl_context, bool, tree *, tree *,
enum deprecated_states);
enum decl_context, bool, tree *, tree *, tree *,
bool *, enum deprecated_states);
static tree grokparms (struct c_arg_info *, bool);
static void layout_array_type (tree);
@ -3128,10 +3128,15 @@ add_flexible_array_elts_to_size (tree decl, tree init)
}
}
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
/* Decode a "typename", such as "int **", returning a ..._TYPE node.
Set *EXPR, if EXPR not NULL, to any expression to be evaluated
before the type name, and set *EXPR_CONST_OPERANDS, if
EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may
appear in a constant expression. */
tree
groktypename (struct c_type_name *type_name)
groktypename (struct c_type_name *type_name, tree *expr,
bool *expr_const_operands)
{
tree type;
tree attrs = type_name->specs->attrs;
@ -3139,7 +3144,8 @@ groktypename (struct c_type_name *type_name)
type_name->specs->attrs = NULL_TREE;
type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
false, NULL, &attrs, DEPRECATED_NORMAL);
false, NULL, &attrs, expr, expr_const_operands,
DEPRECATED_NORMAL);
/* Apply attributes. */
decl_attributes (&type, attrs, 0);
@ -3168,6 +3174,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
{
tree decl;
tree tem;
tree expr = NULL_TREE;
enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
/* An object declared as __attribute__((deprecated)) suppresses
@ -3176,11 +3183,14 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
deprecated_state = DEPRECATED_SUPPRESS;
decl = grokdeclarator (declarator, declspecs,
NORMAL, initialized, NULL, &attributes,
NORMAL, initialized, NULL, &attributes, &expr, NULL,
deprecated_state);
if (!decl)
return 0;
if (expr)
add_stmt (expr);
if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
warning (OPT_Wmain, "%q+D is usually a function", decl);
@ -3668,7 +3678,7 @@ grokparm (const struct c_parm *parm)
{
tree attrs = parm->attrs;
tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
NULL, &attrs, DEPRECATED_NORMAL);
NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
@ -3685,7 +3695,7 @@ push_parm_decl (const struct c_parm *parm)
tree decl;
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
&attrs, DEPRECATED_NORMAL);
&attrs, NULL, NULL, DEPRECATED_NORMAL);
decl_attributes (&decl, attrs, 0);
decl = pushdecl (decl);
@ -3716,10 +3726,11 @@ mark_forward_parm_decls (void)
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
literal. */
literal. NON_CONST is true if the initializers contain something
that cannot occur in a constant expression. */
tree
build_compound_literal (tree type, tree init)
build_compound_literal (tree type, tree init, bool non_const)
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
@ -3772,6 +3783,12 @@ build_compound_literal (tree type, tree init)
rest_of_decl_compilation (decl, 1, 0);
}
if (non_const)
{
complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit);
C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1;
}
return complit;
}
@ -3958,6 +3975,11 @@ warn_variable_length_array (const char *name, tree size)
DECL_ATTRS points to the list of attributes that should be added to this
decl. Any nested attributes that belong on the decl itself will be
added to this list.
If EXPR is not NULL, any expressions that need to be evaluated as
part of evaluating variably modified types will be stored in *EXPR.
If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be
set to indicate whether operands in *EXPR can be used in constant
expressions.
DEPRECATED_STATE is a deprecated_states value indicating whether
deprecation warnings should be suppressed.
@ -3972,7 +3994,8 @@ static tree
grokdeclarator (const struct c_declarator *declarator,
struct c_declspecs *declspecs,
enum decl_context decl_context, bool initialized, tree *width,
tree *decl_attrs, enum deprecated_states deprecated_state)
tree *decl_attrs, tree *expr, bool *expr_const_operands,
enum deprecated_states deprecated_state)
{
tree type = declspecs->type;
bool threadp = declspecs->thread_p;
@ -3994,6 +4017,16 @@ grokdeclarator (const struct c_declarator *declarator,
bool bitfield = width != NULL;
tree element_type;
struct c_arg_info *arg_info = 0;
tree expr_dummy;
bool expr_const_operands_dummy;
if (expr == NULL)
expr = &expr_dummy;
if (expr_const_operands == NULL)
expr_const_operands = &expr_const_operands_dummy;
*expr = declspecs->expr;
*expr_const_operands = declspecs->expr_const_operands;
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
@ -4306,6 +4339,11 @@ grokdeclarator (const struct c_declarator *declarator,
if (size)
{
bool size_maybe_const = true;
bool size_int_const = (TREE_CODE (size) == INTEGER_CST
&& !TREE_OVERFLOW (size));
bool this_size_varies = false;
/* Strip NON_LVALUE_EXPRs since we aren't using as an
lvalue. */
STRIP_TYPE_NOPS (size);
@ -4316,11 +4354,13 @@ grokdeclarator (const struct c_declarator *declarator,
size = integer_one_node;
}
if (pedantic && integer_zerop (size))
size = c_fully_fold (size, false, &size_maybe_const);
if (pedantic && size_maybe_const && integer_zerop (size))
pedwarn (input_location, OPT_pedantic,
"ISO C forbids zero-size array %qs", name);
if (TREE_CODE (size) == INTEGER_CST)
if (TREE_CODE (size) == INTEGER_CST && size_maybe_const)
{
constant_expression_warning (size);
if (tree_int_cst_sgn (size) < 0)
@ -4328,6 +4368,13 @@ grokdeclarator (const struct c_declarator *declarator,
error ("size of array %qs is negative", name);
size = integer_one_node;
}
/* Handle a size folded to an integer constant but
not an integer constant expression. */
if (!size_int_const)
{
this_size_varies = size_varies = 1;
warn_variable_length_array (orig_name, size);
}
}
else if ((decl_context == NORMAL || decl_context == FIELD)
&& current_scope == file_scope)
@ -4340,11 +4387,11 @@ grokdeclarator (const struct c_declarator *declarator,
/* Make sure the array size remains visibly
nonconstant even if it is (eg) a const variable
with known value. */
size_varies = 1;
this_size_varies = size_varies = 1;
warn_variable_length_array (orig_name, size);
}
if (integer_zerop (size))
if (integer_zerop (size) && !this_size_varies)
{
/* A zero-length array cannot be represented with
an unsigned index type, which is what we'll
@ -4359,6 +4406,9 @@ grokdeclarator (const struct c_declarator *declarator,
with the +1 that happens when building TYPE_SIZE. */
if (size_varies)
size = variable_size (size);
if (this_size_varies && TREE_CODE (size) == INTEGER_CST)
size = build2 (COMPOUND_EXPR, TREE_TYPE (size),
integer_zero_node, size);
/* Compute the maximum valid index, that is, size
- 1. Do the calculation in index_type, so that
@ -4386,6 +4436,15 @@ grokdeclarator (const struct c_declarator *declarator,
itype = build_index_type (itype);
}
if (this_size_varies)
{
if (*expr)
*expr = build2 (COMPOUND_EXPR, TREE_TYPE (size),
*expr, size);
else
*expr = size;
*expr_const_operands &= size_maybe_const;
}
}
else if (decl_context == FIELD)
{
@ -5288,10 +5347,15 @@ struct c_typespec
parser_xref_tag (enum tree_code code, tree name)
{
struct c_typespec ret;
tree ref;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
tree ref = lookup_tag (code, name, 0);
ref = lookup_tag (code, name, 0);
/* If this is the right type of tag, return what we found.
(This reference will be shadowed by shadow_tag later if appropriate.)
If this is the wrong type of tag, do not return it. If it was the
@ -5460,7 +5524,7 @@ grokfield (location_t loc,
}
value = grokdeclarator (declarator, declspecs, FIELD, false,
width ? &width : NULL, decl_attrs,
width ? &width : NULL, decl_attrs, NULL, NULL,
DEPRECATED_NORMAL);
finish_decl (value, NULL_TREE, NULL_TREE);
@ -6119,7 +6183,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
c_break_label = c_cont_label = size_zero_node;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
&attributes, DEPRECATED_NORMAL);
&attributes, NULL, NULL, DEPRECATED_NORMAL);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
@ -7132,10 +7196,12 @@ build_null_declspecs (void)
{
struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
ret->type = 0;
ret->expr = 0;
ret->decl_attr = 0;
ret->attrs = 0;
ret->typespec_word = cts_none;
ret->storage_class = csc_none;
ret->expr_const_operands = true;
ret->declspecs_seen_p = false;
ret->type_seen_p = false;
ret->non_sc_seen_p = false;
@ -7657,7 +7723,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
specs->tag_defined_p = true;
if (spec.kind == ctsk_typeof)
{
specs->typedef_p = true;
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;
}

View File

@ -915,7 +915,7 @@ static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
struct c_expr);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
static tree c_parser_expr_list (c_parser *, bool);
static tree c_parser_expr_list (c_parser *, bool, bool);
static void c_parser_omp_construct (c_parser *);
static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
@ -1455,6 +1455,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
/* For a typedef name, record the meaning, not the name.
In case of 'foo foo, bar;'. */
t.spec = lookup_name (value);
t.expr = NULL_TREE;
t.expr_const_operands = true;
}
else
{
@ -1464,6 +1466,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
if (c_parser_next_token_is (parser, CPP_LESS))
proto = c_parser_objc_protocol_refs (parser);
t.spec = objc_get_protocol_qualified_type (value, proto);
t.expr = NULL_TREE;
t.expr_const_operands = true;
}
declspecs_add_type (specs, t);
continue;
@ -1479,6 +1483,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
proto = c_parser_objc_protocol_refs (parser);
t.kind = ctsk_objc;
t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
t.expr = NULL_TREE;
t.expr_const_operands = true;
declspecs_add_type (specs, t);
continue;
}
@ -1526,6 +1532,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
parser->objc_need_raw_identifier = true;
t.kind = ctsk_resword;
t.spec = c_parser_peek_token (parser)->value;
t.expr = NULL_TREE;
t.expr_const_operands = true;
declspecs_add_type (specs, t);
c_parser_consume_token (parser);
break;
@ -1687,6 +1695,8 @@ c_parser_enum_specifier (c_parser *parser)
ret.spec = finish_enum (type, nreverse (values),
chainon (attrs, postfix_attrs));
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
return ret;
}
else if (!ident)
@ -1694,6 +1704,8 @@ c_parser_enum_specifier (c_parser *parser)
c_parser_error (parser, "expected %<{%>");
ret.spec = error_mark_node;
ret.kind = ctsk_tagref;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
return ret;
}
ret = parser_xref_tag (ENUMERAL_TYPE, ident);
@ -1870,6 +1882,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
ret.spec = finish_struct (type, nreverse (contents),
chainon (attrs, postfix_attrs));
ret.kind = ctsk_tagdef;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
return ret;
}
else if (!ident)
@ -1877,6 +1891,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
c_parser_error (parser, "expected %<{%>");
ret.spec = error_mark_node;
ret.kind = ctsk_tagref;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
return ret;
}
ret = parser_xref_tag (code, ident);
@ -2053,6 +2069,8 @@ c_parser_typeof_specifier (c_parser *parser)
struct c_typespec ret;
ret.kind = ctsk_typeof;
ret.spec = error_mark_node;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
c_parser_consume_token (parser);
skip_evaluation++;
@ -2070,7 +2088,7 @@ c_parser_typeof_specifier (c_parser *parser)
in_typeof--;
if (type != NULL)
{
ret.spec = groktypename (type);
ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands);
pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
}
}
@ -2086,22 +2104,10 @@ c_parser_typeof_specifier (c_parser *parser)
error_at (here, "%<typeof%> applied to a bit-field");
ret.spec = TREE_TYPE (expr.value);
was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
/* This should be returned with the type so that when the type
is evaluated, this can be evaluated. For now, we avoid
evaluation when the context might. */
if (!skip_evaluation && was_vm)
{
tree e = expr.value;
/* If the expression is not of a type to which we cannot assign a line
number, wrap the thing in a no-op NOP_EXPR. */
if (DECL_P (e) || CONSTANT_CLASS_P (e))
e = build1 (NOP_EXPR, void_type_node, e);
protected_set_expr_location (e, here);
add_stmt (e);
}
/* This is returned with the type so that when the type is
evaluated, this can be evaluated. */
if (was_vm)
ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
pop_maybe_used (was_vm);
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@ -2858,7 +2864,8 @@ c_parser_attributes (c_parser *parser)
{
c_parser_consume_token (parser);
attr_args = tree_cons (NULL_TREE, arg1,
c_parser_expr_list (parser, false));
c_parser_expr_list (parser, false,
true));
}
}
else
@ -2866,7 +2873,7 @@ c_parser_attributes (c_parser *parser)
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
attr_args = NULL_TREE;
else
attr_args = c_parser_expr_list (parser, false);
attr_args = c_parser_expr_list (parser, false, true);
}
attr = build_tree_list (attr_name, attr_args);
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
@ -3748,8 +3755,9 @@ c_parser_statement_after_labels (c_parser *parser)
}
else
{
stmt
= objc_build_throw_stmt (c_parser_expression (parser).value);
tree expr = c_parser_expression (parser).value;
expr = c_fully_fold (expr, false, NULL);
stmt = objc_build_throw_stmt (expr);
goto expect_semicolon;
}
break;
@ -3810,8 +3818,9 @@ c_parser_condition (c_parser *parser)
location_t loc;
tree cond;
loc = c_parser_peek_token (parser)->location;
cond = c_objc_common_truthvalue_conversion
(loc, c_parser_expression_conv (parser).value);
cond = c_parser_expression_conv (parser).value;
cond = c_objc_common_truthvalue_conversion (loc, cond);
cond = c_fully_fold (cond, false, NULL);
protected_set_expr_location (cond, loc);
if (warn_sequence_point)
verify_sequence_points (cond);
@ -4304,6 +4313,7 @@ c_parser_asm_operands (c_parser *parser, bool convert_p)
expr = c_parser_expression (parser);
if (convert_p)
expr = default_function_array_conversion (expr);
expr.value = c_fully_fold (expr.value, false, NULL);
parser->lex_untranslated_string = true;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
{
@ -4458,7 +4468,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C forbids omitting the middle term of a ?: expression");
/* Make sure first operand is calculated only once. */
exp1.value = save_expr (default_conversion (cond.value));
exp1.value = c_save_expr (default_conversion (cond.value));
cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
skip_evaluation += cond.value == truthvalue_true_node;
}
@ -4482,7 +4492,9 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
exp2 = c_parser_conditional_expression (parser, NULL);
exp2 = default_function_array_conversion (exp2);
skip_evaluation -= cond.value == truthvalue_true_node;
ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
ret.value = build_conditional_expr (cond.value,
cond.original_code == C_MAYBE_CONST_EXPR,
exp1.value, exp2.value);
ret.original_code = ERROR_MARK;
return ret;
}
@ -5012,7 +5024,7 @@ c_parser_alignof_expression (c_parser *parser)
/* alignof ( type-name ). */
skip_evaluation--;
in_alignof--;
ret.value = c_alignof (groktypename (type_name));
ret.value = c_alignof (groktypename (type_name, NULL, NULL));
ret.original_code = ERROR_MARK;
return ret;
}
@ -5200,6 +5212,7 @@ c_parser_postfix_expression (c_parser *parser)
expr = c_parser_expression (parser);
if (TREE_CODE (expr.value) == MODIFY_EXPR)
TREE_NO_WARNING (expr.value) = 1;
if (expr.original_code != C_MAYBE_CONST_EXPR)
expr.original_code = ERROR_MARK;
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
@ -5226,6 +5239,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
e1 = c_parser_expr_no_commas (parser, NULL);
e1.value = c_fully_fold (e1.value, false, NULL);
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
@ -5243,7 +5257,17 @@ c_parser_postfix_expression (c_parser *parser)
}
else
{
expr.value = build_va_arg (e1.value, groktypename (t1));
tree type_expr = NULL_TREE;
expr.value = build_va_arg (e1.value, groktypename (t1,
&type_expr,
NULL));
if (type_expr)
{
expr.value = build2 (C_MAYBE_CONST_EXPR,
TREE_TYPE (expr.value), type_expr,
expr.value);
C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
}
expr.original_code = ERROR_MARK;
}
break;
@ -5270,7 +5294,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
{
tree type = groktypename (t1);
tree type = groktypename (t1, NULL, NULL);
tree offsetof_ref;
if (type == error_mark_node)
offsetof_ref = error_mark_node;
@ -5319,6 +5343,7 @@ c_parser_postfix_expression (c_parser *parser)
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
idx = c_parser_expression (parser).value;
idx = c_fully_fold (idx, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
@ -5365,10 +5390,12 @@ c_parser_postfix_expression (c_parser *parser)
tree c;
c = fold (e1.value);
if (TREE_CODE (c) != INTEGER_CST)
if (TREE_CODE (c) != INTEGER_CST
|| !INTEGRAL_TYPE_P (TREE_TYPE (c)))
error_at (loc,
"first argument to %<__builtin_choose_expr%> not"
" a constant");
constant_expression_warning (c);
expr = integer_zerop (c) ? e3 : e2;
}
break;
@ -5406,8 +5433,8 @@ c_parser_postfix_expression (c_parser *parser)
{
tree e1, e2;
e1 = TYPE_MAIN_VARIANT (groktypename (t1));
e2 = TYPE_MAIN_VARIANT (groktypename (t2));
e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL));
e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL));
expr.value = comptypes (e1, e2)
? build_int_cst (NULL_TREE, 1)
@ -5479,7 +5506,7 @@ c_parser_postfix_expression (c_parser *parser)
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
{
tree type = groktypename (t1);
tree type = groktypename (t1, NULL, NULL);
expr.value = objc_build_encode_expr (type);
expr.original_code = ERROR_MARK;
}
@ -5529,10 +5556,13 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
{
tree type;
struct c_expr init;
bool non_const;
struct c_expr expr;
location_t start_loc;
tree type_expr = NULL_TREE;
bool type_expr_const = true;
start_init (NULL_TREE, NULL, 0);
type = groktypename (type_name);
type = groktypename (type_name, &type_expr, &type_expr_const);
start_loc = c_parser_peek_token (parser)->location;
if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
{
@ -5545,8 +5575,26 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
if (!flag_isoc99)
pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
expr.value = build_compound_literal (type, init.value);
non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
? CONSTRUCTOR_NON_CONST (init.value)
: init.original_code == C_MAYBE_CONST_EXPR);
non_const |= !type_expr_const;
expr.value = build_compound_literal (type, init.value, non_const);
expr.original_code = ERROR_MARK;
if (type_expr)
{
if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR)
{
gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE);
C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr;
}
else
{
gcc_assert (!non_const);
expr.value = build2 (C_MAYBE_CONST_EXPR, type,
type_expr, expr.value);
}
}
return c_parser_postfix_expression_after_primary (parser, expr);
}
@ -5557,6 +5605,7 @@ static struct c_expr
c_parser_postfix_expression_after_primary (c_parser *parser,
struct c_expr expr)
{
struct c_expr orig_expr;
tree ident, idx, exprlist;
location_t loc = c_parser_peek_token (parser)->location;
while (true)
@ -5579,11 +5628,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
exprlist = NULL_TREE;
else
exprlist = c_parser_expr_list (parser, true);
exprlist = c_parser_expr_list (parser, true, false);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
orig_expr = expr;
expr.value = build_function_call (expr.value, exprlist);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) == INTEGER_CST
&& TREE_CODE (orig_expr.value) == FUNCTION_DECL
&& DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
expr.original_code = C_MAYBE_CONST_EXPR;
break;
case CPP_DOT:
/* Structure element reference. */
@ -5681,7 +5736,7 @@ c_parser_expression_conv (c_parser *parser)
}
/* Parse a non-empty list of expressions. If CONVERT_P, convert
functions and arrays to pointers.
functions and arrays to pointers. If FOLD_P, fold the expressions.
nonempty-expr-list:
assignment-expression
@ -5689,13 +5744,15 @@ c_parser_expression_conv (c_parser *parser)
*/
static tree
c_parser_expr_list (c_parser *parser, bool convert_p)
c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p)
{
struct c_expr expr;
tree ret, cur;
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
expr = default_function_array_conversion (expr);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
ret = cur = build_tree_list (NULL_TREE, expr.value);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
@ -5703,6 +5760,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p)
expr = c_parser_expr_no_commas (parser, NULL);
if (convert_p)
expr = default_function_array_conversion (expr);
if (fold_p)
expr.value = c_fully_fold (expr.value, false, NULL);
cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
}
return ret;
@ -6288,7 +6347,7 @@ c_parser_objc_type_name (c_parser *parser)
if (c_parser_next_token_starts_typename (parser))
type_name = c_parser_type_name (parser);
if (type_name)
type = groktypename (type_name);
type = groktypename (type_name, NULL, NULL);
return build_tree_list (quals, type);
}
@ -6394,6 +6453,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
expr = c_parser_expression (parser).value;
expr = c_fully_fold (expr, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
}
else
@ -6529,7 +6589,7 @@ c_parser_objc_receiver (c_parser *parser)
c_parser_consume_token (parser);
return objc_get_class_reference (id);
}
return c_parser_expression (parser).value;
return c_fully_fold (c_parser_expression (parser).value, false, NULL);
}
/* Parse objc-message-args.
@ -6577,7 +6637,7 @@ c_parser_objc_message_args (c_parser *parser)
static tree
c_parser_objc_keywordexpr (c_parser *parser)
{
tree list = c_parser_expr_list (parser, true);
tree list = c_parser_expr_list (parser, true, true);
if (TREE_CHAIN (list) == NULL_TREE)
{
/* Just return the expression, remove a level of
@ -7053,6 +7113,7 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list)
{
location_t expr_loc = c_parser_peek_token (parser)->location;
tree c, t = c_parser_expression (parser).value;
t = c_fully_fold (t, false, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@ -7231,6 +7292,7 @@ c_parser_omp_clause_schedule (c_parser *parser, tree list)
here = c_parser_peek_token (parser)->location;
t = c_parser_expr_no_commas (parser, NULL).value;
t = c_fully_fold (t, false, NULL);
if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
error_at (here, "schedule %<runtime%> does not take "
@ -7430,6 +7492,7 @@ c_parser_omp_atomic (c_parser *parser)
c_parser_skip_to_pragma_eol (parser);
lhs = c_parser_unary_expression (parser).value;
lhs = c_fully_fold (lhs, false, NULL);
switch (TREE_CODE (lhs))
{
case ERROR_MARK:
@ -7491,6 +7554,7 @@ c_parser_omp_atomic (c_parser *parser)
rhs_expr = c_parser_expression (parser);
rhs_expr = default_function_array_conversion (rhs_expr);
rhs = rhs_expr.value;
rhs = c_fully_fold (rhs, false, NULL);
break;
}
stmt = c_finish_omp_atomic (code, lhs, rhs);
@ -7654,6 +7718,7 @@ c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
cond = cond_expr.value;
cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
cond = c_fully_fold (cond, false, NULL);
switch (cond_expr.original_code)
{
case GT_EXPR:

View File

@ -146,6 +146,10 @@ struct lang_type GTY(())
without prototypes. */
#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE)
/* For a CONSTRUCTOR, whether some initializer contains a
subexpression meaning it is not a constant expression. */
#define CONSTRUCTOR_NON_CONST(EXPR) TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (EXPR))
/* Record parser information about an expression that is irrelevant
for code generation alongside a tree representing its value. */
struct c_expr
@ -154,7 +158,9 @@ struct c_expr
tree value;
/* Record the original unary/binary operator of an expression, which may
have been changed by fold, STRING_CST for unparenthesized string
constants, or ERROR_MARK for other expressions (including
constants, C_MAYBE_CONST_EXPR for __builtin_constant_p calls
(even if parenthesized), for subexpressions, and for non-constant
initializers, or ERROR_MARK for other expressions (including
parenthesized expressions). */
enum tree_code original_code;
};
@ -190,6 +196,18 @@ struct c_typespec {
enum c_typespec_kind kind;
/* The specifier itself. */
tree spec;
/* An expression to be evaluated before the type specifier, in the
case of typeof specifiers, or NULL otherwise or if no such
expression is required for a particular typeof specifier. In
particular, when typeof is applied to an expression of variably
modified type, that expression must be evaluated in order to
determine array sizes that form part of the type, but the
expression itself (as opposed to the array sizes) forms no part
of the type and so needs to be recorded separately. */
tree expr;
/* Whether the expression has operands suitable for use in constant
expressions. */
bool expr_const_operands;
};
/* A storage class specifier. */
@ -227,6 +245,9 @@ struct c_declspecs {
whole type, or NULL_TREE if none or a keyword such as "void" or
"char" is used. Does not include qualifiers. */
tree type;
/* Any expression to be evaluated before the type, from a typeof
specifier. */
tree expr;
/* The attributes from a typedef decl. */
tree decl_attr;
/* When parsing, the attributes. Outside the parser, this will be
@ -238,6 +259,9 @@ struct c_declspecs {
enum c_typespec_keyword typespec_word;
/* The storage class specifier, or csc_none if none. */
enum c_storage_class storage_class;
/* Whether any expressions in typeof specifiers may appear in
constant expressions. */
BOOL_BITFIELD expr_const_operands : 1;
/* Whether any declaration specifiers have been seen at all. */
BOOL_BITFIELD declspecs_seen_p : 1;
/* Whether a type specifier has been seen. */
@ -478,7 +502,7 @@ extern tree finish_struct (tree, tree, tree);
extern struct c_arg_info *get_parm_info (bool);
extern tree grokfield (location_t, struct c_declarator *,
struct c_declspecs *, tree, tree *);
extern tree groktypename (struct c_type_name *);
extern tree groktypename (struct c_type_name *, tree *, bool *);
extern tree grokparm (const struct c_parm *);
extern tree implicitly_declare (tree);
extern void keep_next_level (void);
@ -532,6 +556,7 @@ extern bool c_vla_unspec_p (tree x, tree fn);
((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0))
/* in c-typeck.c */
extern bool in_late_binary_op;
extern int in_alignof;
extern int in_sizeof;
extern int in_typeof;
@ -561,7 +586,7 @@ extern struct c_expr parser_build_unary_op (enum tree_code, struct c_expr,
extern struct c_expr parser_build_binary_op (location_t,
enum tree_code, struct c_expr,
struct c_expr);
extern tree build_conditional_expr (tree, tree, tree);
extern tree build_conditional_expr (tree, bool, tree, tree);
extern tree build_compound_expr (tree, tree);
extern tree c_cast_expr (struct c_type_name *, tree);
extern tree build_c_cast (tree, tree);
@ -577,7 +602,7 @@ extern struct c_expr pop_init_level (int);
extern void set_init_index (tree, tree);
extern void set_init_label (tree);
extern void process_init_element (struct c_expr, bool);
extern tree build_compound_literal (tree, tree);
extern tree build_compound_literal (tree, tree, bool);
extern tree c_start_case (tree);
extern void c_finish_case (tree);
extern tree build_asm_expr (tree, tree, tree, tree, bool);

File diff suppressed because it is too large Load Diff

View File

@ -663,6 +663,10 @@ A @code{typeof}-construct can be used anywhere a typedef name could be
used. For example, you can use it in a declaration, in a cast, or inside
of @code{sizeof} or @code{typeof}.
The operand of @code{typeof} is evaluated for its side effects if and
only if it is an expression of variably modified type or the name of
such a type.
@code{typeof} is often useful in conjunction with the
statements-within-expressions feature. Here is how the two together can
be used to define a safe ``maximum'' macro that operates on any
@ -6635,9 +6639,8 @@ depending on the arguments' types. For example:
You can use the built-in function @code{__builtin_choose_expr} to
evaluate code depending on the value of a constant expression. This
built-in function returns @var{exp1} if @var{const_exp}, which is a
constant expression that must be able to be determined at compile time,
is nonzero. Otherwise it returns 0.
built-in function returns @var{exp1} if @var{const_exp}, which is an
integer constant expression, is nonzero. Otherwise it returns 0.
This built-in function is analogous to the @samp{? :} operator in C,
except that the expression returned has its type unaltered by promotion
@ -6716,7 +6719,11 @@ static const int table[] = @{
@noindent
This is an acceptable initializer even if @var{EXPRESSION} is not a
constant expression. GCC must be more conservative about evaluating the
constant expression, including the case where
@code{__builtin_constant_p} returns 1 because @var{EXPRESSION} can be
folded to a constant but @var{EXPRESSION} contains operands that would
not otherwize be permitted in a static initializer (for example,
@code{0 && foo ()}). GCC must be more conservative about evaluating the
built-in in this case, because it has no opportunity to perform
optimization.

View File

@ -1,3 +1,13 @@
2009-03-29 Joseph Myers <joseph@codesourcery.com>
PR c/456
PR c/5675
PR c/19976
PR c/29116
PR c/31871
PR c/35198
* objc-act.c (objc_finish_try_stmt): Set in_late_binary_op.
2008-12-05 Sebastian Pop <sebastian.pop@amd.com>
PR bootstrap/38262

View File

@ -1,6 +1,6 @@
/* Implement classes and message passing for Objective C.
Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Steve Naroff.
This file is part of GCC.
@ -3885,12 +3885,15 @@ objc_finish_try_stmt (void)
/* If we're doing Darwin setjmp exceptions, build the big nasty. */
if (flag_objc_sjlj_exceptions)
{
bool save = in_late_binary_op;
in_late_binary_op = true;
if (!cur_try_context->finally_body)
{
cur_try_context->finally_locus = input_location;
cur_try_context->end_finally_locus = input_location;
}
stmt = next_sjlj_build_try_catch_finally ();
in_late_binary_op = save;
}
else
{

View File

@ -1,3 +1,40 @@
2009-03-29 Joseph Myers <joseph@codesourcery.com>
PR c/456
PR c/5675
PR c/19976
PR c/29116
PR c/31871
PR c/35198
* gcc.c-torture/compile/20081108-1.c,
gcc.c-torture/compile/20081108-2.c,
gcc.c-torture/compile/20081108-3.c, gcc.dg/bconstp-2.c,
gcc.dg/bconstp-3.c, gcc.dg/bconstp-4.c, gcc.dg/c90-const-expr-6.c,
gcc.dg/c90-const-expr-7.c, gcc.dg/c90-const-expr-8.c,
gcc.dg/c90-const-expr-9.c, gcc.dg/c90-const-expr-10.c,
gcc.dg/c90-const-expr-11.c, gcc.dg/c99-const-expr-6.c,
gcc.dg/c99-const-expr-7.c, gcc.dg/c99-const-expr-8.c,
gcc.dg/c99-const-expr-9.c, gcc.dg/c99-const-expr-10.c,
gcc.dg/c99-const-expr-11.c, gcc.dg/c99-const-expr-12.c,
gcc.dg/c99-const-expr-13.c, gcc.dg/compare10.c,
gcc.dg/gnu89-const-expr-1.c, gcc.dg/gnu89-const-expr-2.c,
gcc.dg/gnu99-const-expr-1.c, gcc.dg/gnu99-const-expr-2.c,
gcc.dg/gnu99-const-expr-3.c, gcc.dg/vla-12.c, gcc.dg/vla-13.c,
gcc.dg/vla-14.c, gcc.dg/vla-15.c, gcc.dg/vla-16.c: New tests.
* gcc.dg/c90-const-expr-1.c, gcc.dg/c90-const-expr-2.c,
gcc.dg/c90-const-expr-3.c, gcc.dg/c99-const-expr-2.c,
gcc.dg/c99-const-expr-3.c, gcc.dg/c99-static-1.c: Remove XFAILs.
* gcc.dg/c90-const-expr-2.c: Use ZERO in place of 0 in another
case.
* gcc.dg/overflow-warn-1.c, gcc.dg/overflow-warn-2.c,
gcc.dg/overflow-warn-3.c, gcc.dg/overflow-warn-4.c: Remove
XFAILs. Update expected messages.
* gcc.dg/pr14649-1.c, gcc.dg/pr19984.c, gcc.dg/pr25682.c: Update
expected messages.
* gcc.dg/real-const-1.c: Replace with test from original PR.
* gcc.dg/vect/pr32230.c: Use intermediate cast to __PTRDIFF_TYPE__
when casting from non-constant integer to pointer.
2009-03-29 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/forwprop-11.c: New testcase.

View File

@ -0,0 +1,11 @@
/* Test function call with function designator involving VLA
side-effects does not lead to an ICE. */
void f (void);
void g (void);
void
h (int a, void *b)
{
((void *)(int (*)[++a])b ? f : g) ();
}

View File

@ -0,0 +1,4 @@
/* Test boolean conversion as part of returning unsigned value does
not lead to an ICE. */
_Bool f(unsigned a) { return a & 1; }

View File

@ -0,0 +1,4 @@
/* Test boolean conversion of an overflowing integer return value does
not lead to an ICE. */
_Bool f(void) { return __INT_MAX__ + 1; }

View File

@ -0,0 +1,27 @@
/* As bconstp-1.c, but with the __builtin_constant_p calls
parenthesized. */
/* { dg-do compile } */
/* This test checks that builtin_constant_p can be used safely in
initializers for static data. The macro X() defined below should
be an acceptable initializer expression no matter how complex its
argument is. */
extern int a;
extern int b;
extern int foo(void);
extern int bar(void);
#define X(exp) ((__builtin_constant_p(exp)) ? (exp) : -1)
const short tests[] = {
X(0),
X(a),
X(0 && a),
X(a && b),
X(foo()),
X(0 && foo()),
X(a && foo()),
X(foo() && bar())
};

View File

@ -0,0 +1,27 @@
/* As bconstp-1.c, but with the __builtin_constant_p calls inside
__builtin_choose_expr. */
/* { dg-do compile } */
/* This test checks that builtin_constant_p can be used safely in
initializers for static data. The macro X() defined below should
be an acceptable initializer expression no matter how complex its
argument is. */
extern int a;
extern int b;
extern int foo(void);
extern int bar(void);
#define X(exp) (__builtin_choose_expr(1, __builtin_constant_p(exp), 1) ? (exp) : -1)
const short tests[] = {
X(0),
X(a),
X(0 && a),
X(a && b),
X(foo()),
X(0 && foo()),
X(a && foo()),
X(foo() && bar())
};

View File

@ -0,0 +1,10 @@
/* Test that a condition is not counted as a call to
__builtin_constant_p if that call is itself inside a conditional
expression with __builtin_constant_p condition. */
/* { dg-do compile } */
extern int foo(void);
#define X(exp) (__builtin_choose_expr(1, __builtin_constant_p(exp), 1) ? (exp) : -1)
const int x = ((__builtin_constant_p(1) ? __builtin_constant_p (0 && foo()) : 0) ? (0 && foo()) : -1); /* { dg-error "initializer element is not a constant expression" } */

View File

@ -15,9 +15,9 @@ void
foo (void)
{
int i;
static int j = (1 ? 0 : (i = 2)); /* { dg-error "initial" "assignment" { xfail *-*-* } } */
static int k = (1 ? 0 : ++i); /* { dg-error "initial" "increment" { xfail *-*-* } } */
static int l = (1 ? 0 : --i); /* { dg-error "initial" "decrement" { xfail *-*-* } } */
static int m = (1 ? 0 : bar ()); /* { dg-error "initial" "function call" { xfail *-*-* } } */
static int n = (1 ? 0 : (2, 3)); /* { dg-error "initial" "comma" { xfail *-*-* } } */
static int j = (1 ? 0 : (i = 2)); /* { dg-error "initial" "assignment" } */
static int k = (1 ? 0 : ++i); /* { dg-error "initial" "increment" } */
static int l = (1 ? 0 : --i); /* { dg-error "initial" "decrement" } */
static int m = (1 ? 0 : bar ()); /* { dg-error "initial" "function call" } */
static int n = (1 ? 0 : (2, 3)); /* { dg-error "initial" "comma" } */
}

View File

@ -0,0 +1,28 @@
/* Test for constant expressions: invalid null pointer constants in
various contexts (make sure NOPs are not inappropriately
stripped). */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
void *p = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
struct s { void *a; } q = { (__SIZE_TYPE__)(void *)0 }; /* { dg-error "without a cast" } */
void *
f (void)
{
void *r;
r = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
return (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
}
void g (void *); /* { dg-message "but argument is of type" } */
void
h (void)
{
g ((__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
}
void g2 (int, void *); /* { dg-message "but argument is of type" } */
void
h2 (void)
{
g2 (0, (__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
}

View File

@ -0,0 +1,27 @@
/* Test for constant expressions: C90 aggregate initializers requiring
constant expressions. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors -O2" } */
#include <float.h>
#include <limits.h>
double atan(double);
struct s { double d; };
struct t { int i; };
void
f (void)
{
/* As in PR 14649 for static initializers. */
struct s a = { atan (1.0) }; /* { dg-error "is not a constant expression|near initialization" } */
/* Overflow. */
struct t b = { INT_MAX + 1 }; /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
struct t c = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 23 } */
/* Bad operator outside sizeof. */
struct s d = { 1 ? 1.0 : atan (a.d) }; /* { dg-error "is not a constant expression|near initialization" } */
}

View File

@ -34,10 +34,10 @@ foo (void)
{
ASSERT_NPC (0);
ASSERT_NPC ((void *)0);
ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(0, ZERO)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
/* This last one is a null pointer constant in C99 only. */
ASSERT_NOT_NPC ((void *)(1 ? 0 : (0, 0))); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(1 ? ZERO : (0, ZERO))); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}

View File

@ -28,19 +28,19 @@ foo (void)
ASSERT_NPC (0);
ASSERT_NOT_NPC (ZERO);
ASSERT_NPC (0 + 0);
ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (+0);
ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (-0);
ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC ((char) 0);
ASSERT_NOT_NPC ((char) ZERO);
ASSERT_NPC ((int) 0);
ASSERT_NOT_NPC ((int) ZERO);
ASSERT_NPC ((int) 0.0);
ASSERT_NOT_NPC ((int) DZERO);
ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}

View File

@ -0,0 +1,53 @@
/* Test for constant expressions: operands and casts not permitted in
integer constant expressions. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
/* PR 29116. */
int n = 0, p[n * 0 + 1]; /* { dg-error "variabl|can't be evaluated" } */
/* PR 31871. */
extern int c[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */
/* Implicit conversions from floating-point constants are not OK,
although explicit ones are. */
extern int c1[1.0 ? 1 : 0]; /* { dg-error "variab|can't be evaluated" } */
extern int c2[(int)1.0 ? 1 : 0];
extern int c3[1.0 && 1]; /* { dg-error "variab|can't be evaluated" } */
extern int c4[(int)1.0 && 1];
extern int c5[1.0 || 1]; /* { dg-error "variab|can't be evaluated" } */
extern int c6[(int)1.0 || 1];
/* Similar with various other cases where integer constant expressions
are required. */
struct s {
int a : (n * 0 + 1); /* { dg-error "constant" } */
};
enum e {
E = (1 + ((__PTRDIFF_TYPE__) (void *) 0)), /* { dg-error "constant" } */
E2 = 0
};
enum f {
F = (1 ? 1 : n), /* { dg-error "constant" } */
F2 = 0
};
void
f (int a)
{
int v[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */
switch (a)
{
case (n * 0 + 1): /* { dg-error "constant" } */
;
}
}

View File

@ -0,0 +1,35 @@
/* Test for constant expressions: overflow and constant expressions;
see also overflow-warn-*.c for some other cases. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
#include <float.h>
int a = DBL_MAX; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 9 } */
int b = (int) DBL_MAX; /* { dg-error "overflow" "" } */
unsigned int c = -1.0; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
unsigned int d = (unsigned)-1.0; /* { dg-error "overflow" } */
int e = 0 << 1000; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 16 } */
int f = 0 << -1; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 18 } */
int g = 0 >> 1000; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 20 } */
int h = 0 >> -1; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 22 } */
int b1 = (0 ? (int) DBL_MAX : 0);
unsigned int d1 = (0 ? (unsigned int)-1.0 : 0);
int e1 = (0 ? 0 << 1000 : 0);
int f1 = (0 ? 0 << -1 : 0);
int g1 = (0 ? 0 >> 1000 : 0);
int h1 = (0 ? 0 >> -1: 0);
int i = -1 << 0;
int j[1] = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 34 } */

View File

@ -0,0 +1,27 @@
/* Test for constant expressions: overflow and constant expressions
with -fwrapv: overflows still count as such for the purposes of
constant expressions even when they have defined values at
runtime. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors -fwrapv" } */
#include <limits.h>
enum e {
E0 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
E1 = 0 * (INT_MIN / -1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 14 } */
E2 = 0 * (INT_MAX * INT_MAX), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 16 } */
E3 = 0 * (INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 18 } */
E4 = 0 * (unsigned)(INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 20 } */
E5 = 0 * -INT_MIN, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 22 } */
E6 = 0 * !-INT_MIN, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "not an integer constant" "constant" { target *-*-* } 24 } */
E7 = INT_MIN % -1 /* Not an overflow. */
};

View File

@ -0,0 +1,26 @@
/* Test for constant expressions: __builtin_offsetof allowed in
integer constant expressions but not traditional offsetof
expansion. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
struct s {
int a;
};
struct t {
struct s a;
int b[2];
};
#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__) &((TYPE *)0)->MEMBER)
enum e {
E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */
E2 = old_offsetof (struct t, a.a), /* { dg-error "constant" } */
E3 = old_offsetof (struct t, b[1]), /* { dg-error "constant" } */
E4 = __builtin_offsetof (struct s, a),
E5 = __builtin_offsetof (struct t, a.a),
E6 = __builtin_offsetof (struct t, b[1])
};

View File

@ -0,0 +1,28 @@
/* Test for constant expressions: invalid null pointer constants in
various contexts (make sure NOPs are not inappropriately
stripped). */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
void *p = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
struct s { void *a; } q = { (__SIZE_TYPE__)(void *)0 }; /* { dg-error "without a cast" } */
void *
f (void)
{
void *r;
r = (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
return (__SIZE_TYPE__)(void *)0; /* { dg-error "without a cast" } */
}
void g (void *); /* { dg-message "but argument is of type" } */
void
h (void)
{
g ((__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
}
void g2 (int, void *); /* { dg-message "but argument is of type" } */
void
h2 (void)
{
g2 (0, (__SIZE_TYPE__)(void *)0); /* { dg-error "without a cast" } */
}

View File

@ -0,0 +1,46 @@
/* Test for constant expressions: cases involving VLAs. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
/* It appears address constants may contain casts to variably modified
types. Whether they should be permitted was discussed in
<http://groups.google.com/group/comp.std.c/msg/923eee5ab690fd98>
<LV7g2Vy3ARF$Ew9Q@romana.davros.org>; since static pointers to VLAs
are definitely permitted within functions and may be initialized
and such initialization involves implicit conversion to a variably
modified type, allowing explicit casts seems appropriate. Thus,
GCC allows them as long as the "evaluated" size expressions do not
contain the various operators not permitted to be evaluated in a
constant expression, and as long as the result is genuinely
constant (meaning that pointer arithmetic using the size of the VLA
is generally not permitted). */
static int sa[100];
volatile int nv;
int
f (int m, int n)
{
static int (*a1)[n] = &sa;
static int (*a2)[n] = (int (*)[n])sa;
static int (*a3)[n] = (int (*)[(int){n}])sa;
static int (*a4)[n] = (int (*)[(int){m++}])sa; /* { dg-error "constant" } */
static int (*a5)[n] = (int (*)[(int){++m}])sa; /* { dg-error "constant" } */
static int (*a6)[n] = (int (*)[(int){m--}])sa; /* { dg-error "constant" } */
static int (*a7)[n] = (int (*)[(int){--m}])sa; /* { dg-error "constant" } */
static int (*a8)[n] = (int (*)[(m=n)])sa; /* { dg-error "constant" } */
static int (*a9)[n] = (int (*)[(m+=n)])sa; /* { dg-error "constant" } */
static int (*a10)[n] = (int (*)[f(m,n)])sa; /* { dg-error "constant" } */
static int (*a11)[n] = (int (*)[(m,n)])sa; /* { dg-error "constant" } */
static int (*a12)[n] = (int (*)[sizeof(int[n])])sa;
static int (*a13)[n] = (int (*)[sizeof(int[m++])])sa; /* { dg-error "constant" } */
static int (*a14)[n] = (int (*)[sizeof(*a1)])sa;
static int (*a15)[n] = (int (*)[sizeof(*(int (*)[n])sa)])sa;
static int (*a16)[n] = (int (*)[sizeof(*(int (*)[m++])sa)])sa; /* { dg-error "constant" } */
static int (*a17)[n] = (int (*)[nv])sa;
typedef int (*vmt)[m++];
static int (*a18)[n] = (vmt)sa;
return n;
}

View File

@ -0,0 +1,23 @@
/* Test for constant expressions: VLA size constraints. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
void
f (int m)
{
/* An array size that is a constant expression, not just an integer
constant expression, must be checked for being positive, but only
an integer constant expression makes it not a VLA (which affects
certain compatibility checks, in particular). */
int a1[0]; /* { dg-error "zero" } */
int a2[-1]; /* { dg-error "negative" } */
int a3[(int)(double)0.0]; /* { dg-error "zero" } */
int a4[(int)-1.0]; /* { dg-error "negative" } */
int a5[(int)+1.0];
int a6[(int)+2.0];
void *p = (m ? &a5 : &a6);
int a7[(int)1.0];
int a8[(int)2.0];
void *q = (m ? &a7 : &a8); /* { dg-error "pointer type mismatch in conditional expression" } */
}

View File

@ -0,0 +1,15 @@
/* Test for constant expressions: VLA size constraints with
-frounding-math. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors -frounding-math" } */
void
f (void)
{
/* With -frounding-math, presume that floating-point expressions
that may depend on the rounding mode do not count as arithmetic
constant expressions, and so arrays involving such expressions in
their sizes do not have the size checked for being negative. */
int a1[(int)(-5.0/3.0)];
}

View File

@ -34,10 +34,10 @@ foo (void)
{
ASSERT_NPC (0);
ASSERT_NPC ((void *)0);
ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(void *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(char *)0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(0, ZERO)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((void *)(&"Foobar"[0] - &"Foobar"[0])); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
/* This last one is a null pointer constant in C99 only. */
ASSERT_NPC ((void *)(1 ? 0 : (0, 0)));
}

View File

@ -27,19 +27,19 @@ foo (void)
ASSERT_NPC (0);
ASSERT_NOT_NPC (ZERO);
ASSERT_NPC (0 + 0);
ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (ZERO + 0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC (ZERO + ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (+0);
ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (+ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC (-0);
ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC (-ZERO); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NPC ((char) 0);
ASSERT_NOT_NPC ((char) ZERO);
ASSERT_NPC ((int) 0);
ASSERT_NOT_NPC ((int) ZERO);
ASSERT_NPC ((int) 0.0);
ASSERT_NOT_NPC ((int) DZERO);
ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" { xfail *-*-* } } */
ASSERT_NOT_NPC ((int) +0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((int) (0.0+0.0)); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
ASSERT_NOT_NPC ((int) (double)0.0); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
}

View File

@ -0,0 +1,62 @@
/* Test for constant expressions: operands and casts not permitted in
integer constant expressions. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
/* PR 29116. */
int n = 0, p[n * 0 + 1]; /* { dg-error "variabl" } */
/* PR 31871. */
extern int c[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab" } */
/* Implicit conversions from floating-point constants are not OK,
although explicit ones are. */
extern int c1[1.0 ? 1 : 0]; /* { dg-error "variab" } */
extern int c2[(int)1.0 ? 1 : 0];
extern int c3[1.0 && 1]; /* { dg-error "variab" } */
extern int c4[(int)1.0 && 1];
extern int c5[1.0 || 1]; /* { dg-error "variab" } */
extern int c6[(int)1.0 || 1];
/* Similar with various other cases where integer constant expressions
are required. */
struct s {
int a : (n * 0 + 1); /* { dg-error "constant" } */
};
enum e {
E = (1 + ((__PTRDIFF_TYPE__) (void *) 0)), /* { dg-error "constant" } */
E2 = 0
};
enum f {
F = (1 ? 1 : n), /* { dg-error "constant" } */
F2 = 0
};
/* Presume that a compound literal, being a reference to an anonymous
variable, is not allowed in an integer constant expression
regardless of what initializers it contains. */
enum g {
G = (1 ? 1 : (int){0}), /* { dg-error "constant" } */
G2 = 0
};
int v[2] = { [(n * 0 + 1)] = 1 }; /* { dg-error "constant|near initialization" } */
void
f (int a)
{
switch (a)
{
case (n * 0 + 1): /* { dg-error "constant" } */
;
}
}

View File

@ -0,0 +1,43 @@
/* Test for constant expressions: overflow and constant expressions;
see also overflow-warn-*.c for some other cases. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
#include <float.h>
#include <limits.h>
int a = DBL_MAX; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 10 } */
int b = (int) DBL_MAX; /* { dg-error "overflow" "" } */
unsigned int c = -1.0; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 13 } */
unsigned int d = (unsigned)-1.0; /* { dg-error "overflow" } */
int e = 0 << 1000; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 17 } */
int f = 0 << -1; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 19 } */
int g = 0 >> 1000; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 21 } */
int h = 0 >> -1; /* { dg-warning "shift count" } */
/* { dg-error "constant" "constant" { target *-*-* } 23 } */
int b1 = (0 ? (int) DBL_MAX : 0);
unsigned int d1 = (0 ? (unsigned int)-1.0 : 0);
int e1 = (0 ? 0 << 1000 : 0);
int f1 = (0 ? 0 << -1 : 0);
int g1 = (0 ? 0 >> 1000 : 0);
int h1 = (0 ? 0 >> -1: 0);
/* Allowed for now, but actually undefined behavior in C99. */
int i = -1 << 0;
int j[1] = { DBL_MAX }; /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 36 } */
int array[2] = { [0 * (INT_MAX + 1)] = 0 }; /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 39 } */
_Bool k = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 42 } */

View File

@ -0,0 +1,27 @@
/* Test for constant expressions: overflow and constant expressions
with -fwrapv: overflows still count as such for the purposes of
constant expressions even when they have defined values at
runtime. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors -fwrapv" } */
#include <limits.h>
enum e {
E0 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 12 } */
E1 = 0 * (INT_MIN / -1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 14 } */
E2 = 0 * (INT_MAX * INT_MAX), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 16 } */
E3 = 0 * (INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 18 } */
E4 = 0 * (unsigned)(INT_MIN - 1), /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 20 } */
E5 = 0 * -INT_MIN, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 22 } */
E6 = 0 * !-INT_MIN, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "not an integer constant" "constant" { target *-*-* } 24 } */
E7 = INT_MIN % -1 /* Not an overflow. */
};

View File

@ -0,0 +1,26 @@
/* Test for constant expressions: __builtin_offsetof allowed in
integer constant expressions but not traditional offsetof
expansion. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
struct s {
int a;
};
struct t {
struct s a;
int b[2];
};
#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__) &((TYPE *)0)->MEMBER)
enum e {
E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */
E2 = old_offsetof (struct t, a.a), /* { dg-error "constant" } */
E3 = old_offsetof (struct t, b[1]), /* { dg-error "constant" } */
E4 = __builtin_offsetof (struct s, a),
E5 = __builtin_offsetof (struct t, a.a),
E6 = __builtin_offsetof (struct t, b[1])
};

View File

@ -27,7 +27,7 @@ static int f4(void);
void g4(void) { sizeof(int (*)[f4()]); }
/* Constraint violation (VLA). */
static int f5(void); /* { dg-error "used but never defined" "VLA" { xfail *-*-* } } */
static int f5(void); /* { dg-error "used but never defined" "VLA" } */
void g5(void) { sizeof(int [0 ? f5() : 1]); }
/* OK (non-constant sizeof inside constant sizeof). */

View File

@ -0,0 +1,16 @@
/* Test for bogus -Wsign-compare warnings that appeared when not
folding operands before warning. */
/* { dg-do compile } */
/* { dg-options "-Wsign-compare" } */
int
test_compare (int a, unsigned b)
{
return (b > 8 * (a ? 4 : 8));
}
unsigned int
test_conditional (int a, unsigned b, int c)
{
return (c ? b : 8 * (a ? 4 : 8));
}

View File

@ -0,0 +1,47 @@
/* Test for constant expressions: GNU extensions. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu89" } */
int n;
void
f (void)
{
int i = 0;
int a[n];
enum e1 {
/* Integer constant expressions may not contain statement
expressions (not a permitted operand). */
E1 = (1 ? 0 : ({ 0; })), /* { dg-error "constant" } */
/* Real and imaginary parts act like other arithmetic
operators. */
E2 = __real__ (1 ? 0 : i++), /* { dg-error "constant" } */
E3 = __real__ 0,
E4 = __imag__ (1 ? 0 : i++), /* { dg-error "constant" } */
E5 = __imag__ 0,
/* __alignof__ always constant. */
E6 = __alignof__ (int[n]),
E7 = __alignof__ (a),
/* __extension__ ignored for constant expression purposes. */
E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant" } */
E9 = __extension__ 0,
/* Conditional expressions with omitted arguments act like the
standard type. */
E10 = (1 ? : i++), /* { dg-error "constant" } */
E11 = (1 ? : 0)
};
enum e2 {
/* Complex integer constants may be cast directly to integer
types, but not after further arithmetic on them. */
F1 = (int) (_Complex int) 2i, /* { dg-error "constant" } */
F2 = (int) +2i, /* { dg-error "constant" } */
F3 = (int) (1 + 2i), /* { dg-error "constant" } */
F4 = (int) 2i
};
static double dr = __real__ (1.0 + 2.0i);
static double di = __imag__ (1.0 + 2.0i);
/* Statement expressions allowed in unevaluated subexpressions in
initializers in gnu99 but not gnu89. */
static int j = (1 ? 0 : ({ 0; })); /* { dg-warning "constant expression" } */
}

View File

@ -0,0 +1,23 @@
/* Test for constant expressions: __builtin_choose_expr. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu89 -pedantic-errors" } */
#include <limits.h>
int a, b, c;
void
f (void)
{
/* __builtin_choose_expr acts exactly like the chosen argument for
all constant expression purposes. */
enum e {
E1 = __builtin_choose_expr (1, 1, ++b)
};
/* The first argument to __builtin_choose_expr must be an integer
constant expression. */
a = __builtin_choose_expr ((void *)0, b, c); /* { dg-error "constant" } */
a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
}

View File

@ -0,0 +1,47 @@
/* Test for constant expressions: GNU extensions. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99" } */
int n;
void
f (void)
{
int i = 0;
int a[n];
enum e1 {
/* Integer constant expressions may not contain statement
expressions (not a permitted operand). */
E1 = (1 ? 0 : ({ 0; })), /* { dg-error "constant" } */
/* Real and imaginary parts act like other arithmetic
operators. */
E2 = __real__ (1 ? 0 : i++), /* { dg-error "constant" } */
E3 = __real__ 0,
E4 = __imag__ (1 ? 0 : i++), /* { dg-error "constant" } */
E5 = __imag__ 0,
/* __alignof__ always constant. */
E6 = __alignof__ (int[n]),
E7 = __alignof__ (a),
/* __extension__ ignored for constant expression purposes. */
E8 = __extension__ (1 ? 0 : i++), /* { dg-error "constant" } */
E9 = __extension__ 0,
/* Conditional expressions with omitted arguments act like the
standard type. */
E10 = (1 ? : i++), /* { dg-error "constant" } */
E11 = (1 ? : 0)
};
enum e2 {
/* Complex integer constants may be cast directly to integer
types, but not after further arithmetic on them. */
F1 = (int) (_Complex int) 2i, /* { dg-error "constant" } */
F2 = (int) +2i, /* { dg-error "constant" } */
F3 = (int) (1 + 2i), /* { dg-error "constant" } */
F4 = (int) 2i
};
static double dr = __real__ (1.0 + 2.0i);
static double di = __imag__ (1.0 + 2.0i);
/* Statement expressions allowed in unevaluated subexpressions in
initializers in gnu99 but not gnu89. */
static int j = (1 ? 0 : ({ 0; }));
}

View File

@ -0,0 +1,23 @@
/* Test for constant expressions: __builtin_choose_expr. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99 -pedantic-errors" } */
#include <limits.h>
int a, b, c;
void
f (void)
{
/* __builtin_choose_expr acts exactly like the chosen argument for
all constant expression purposes. */
enum e {
E1 = __builtin_choose_expr (1, 1, ++b)
};
/* The first argument to __builtin_choose_expr must be an integer
constant expression. */
a = __builtin_choose_expr ((void *)0, b, c); /* { dg-error "constant" } */
a = __builtin_choose_expr (0 * (INT_MAX + 1), b, c); /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
}

View File

@ -0,0 +1,32 @@
/* Test for constant expressions: cases involving VLAs and typeof. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=gnu99 -pedantic-errors" } */
/* It appears address constants may contain casts to variably modified
types. Whether they should be permitted was discussed in
<http://groups.google.com/group/comp.std.c/msg/923eee5ab690fd98>
<LV7g2Vy3ARF$Ew9Q@romana.davros.org>; since static pointers to VLAs
are definitely permitted within functions and may be initialized
and such initialization involves implicit conversion to a variably
modified type, allowing explicit casts seems appropriate. Thus,
GCC allows them as long as the "evaluated" size expressions do not
contain the various operators not permitted to be evaluated in a
constant expression, and as long as the result is genuinely
constant (meaning that pointer arithmetic using the size of the VLA
is generally not permitted). */
static int sa[100];
int
f (int m, int n)
{
static int (*a1)[n] = &sa;
static int (*a2)[n] = (__typeof__(int (*)[n]))sa;
static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */
static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa;
static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */
static int (*a6)[n] = (__typeof__((int (*)[100])(int (*)[m++])sa))sa;
static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */
return n;
}

View File

@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* Again, overflow in evaluated subexpression. */
E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
@ -28,6 +28,7 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-error "not an integer constant" "integer constant" { target *-*-* } 30 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
};
@ -46,9 +47,10 @@ static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 48 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 49 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 50 } */
/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 51 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 51 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@ -57,6 +59,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
/* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 61 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
;

View File

@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* Again, overflow in evaluated subexpression. */
E6 = 0 * (INT_MAX + 1), /* { dg-warning "integer overflow in expression" } */
@ -28,6 +28,7 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-error "not an integer constant" "integer constant" { target *-*-* } 30 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
};
@ -46,9 +47,10 @@ static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" }
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 48 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 49 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 50 } */
/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 51 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 51 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@ -57,6 +59,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
/* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 61 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
;
@ -82,23 +85,23 @@ void
h2 (void)
{
fsc (SCHAR_MAX + 1);
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 84 } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 87 } */
fsc (SCHAR_MIN - 1); /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 86 } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 89 } */
fsc (UCHAR_MAX);
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 88 } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 91 } */
fsc (UCHAR_MAX + 1); /* { dg-warning "overflow in implicit constant conversion" } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 90 } */
/* { dg-warning "passing argument 1 of 'fsc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 93 } */
fuc (-1);
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 92 } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 95 } */
fuc (UCHAR_MAX + 1); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 94 } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 97 } */
fuc (SCHAR_MIN);
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 96 } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 99 } */
fuc (SCHAR_MIN - 1); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 98 } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 101 } */
fuc (-UCHAR_MAX); /* { dg-warning "large integer implicitly truncated to unsigned type" } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 100 } */
/* { dg-warning "passing argument 1 of 'fuc' with different width due to prototype" "-Wtraditional-conversion" { target *-*-* } 103 } */
}
void fui (unsigned int);
@ -122,11 +125,11 @@ h2i (int x)
fsi (UINT_MAX); /* { dg-warning "passing argument 1 of 'fsi' as signed due to prototype" } */
si = UINT_MAX;
fui (-1);
/* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 124 } */
/* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 127 } */
ui = -1;
ui = x ? -1 : 1U;
fui (INT_MIN);
/* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 128 } */
/* { dg-warning "passing argument 1 of 'fui' as unsigned due to prototype" "-Wtraditional-conversion" { target *-*-* } 131 } */
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}

View File

@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@ -30,8 +30,9 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-error "not an integer constant" "integer constant" { target *-*-* } 32 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 33 } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 34 } */
};
void
@ -45,16 +46,17 @@ f (void)
/* But this expression does need to be constant. */
static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 47 } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 48 } */
/* The first two of these involve overflow, so are not null pointer
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 53 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 53 } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 54 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 54 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 56 } */
/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 57 } */
/* { dg-warning "initialization makes pointer from integer without a cast" "null" { target *-*-* } 57 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@ -63,9 +65,10 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
/* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 67 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 67 } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 70 } */
;
}
}

View File

@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
/* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target *-*-* } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@ -30,8 +30,9 @@ enum e {
struct s {
int a;
int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-error "not an integer constant" "integer constant" { target *-*-* } 32 } */
int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 33 } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 34 } */
};
void
@ -45,16 +46,17 @@ f (void)
/* But this expression does need to be constant. */
static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 47 } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 48 } */
/* The first two of these involve overflow, so are not null pointer
constants. The third has the overflow in an unevaluated
subexpression, so is a null pointer constant. */
void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 53 } */
/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 53 } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 54 } */
/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 54 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
/* { dg-error "initialization makes pointer from integer without a cast" "null" { xfail *-*-* } 56 } */
/* { dg-error "initializer element is not constant" "constant" { target *-*-* } 57 } */
/* { dg-error "initialization makes pointer from integer without a cast" "null" { target *-*-* } 57 } */
void *r = (1 ? 0 : INT_MAX+1);
void
@ -63,9 +65,10 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
/* { dg-error "case label does not reduce to an integer constant" "constant" { target *-*-* } 67 } */
;
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 67 } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 70 } */
;
}
}

View File

@ -4,7 +4,7 @@
double atan(double);
const double pi = 4*atan(1.0); /* { dg-warning "(not constant)|(near initialization)" } */
const double pi = 4*atan(1.0); /* { dg-warning "not a constant expression" } */
const double ok = 4*__builtin_atan(1.0);

View File

@ -5,7 +5,7 @@
double nan (const char *);
const double nok = nan (""); /* { dg-warning "(not constant)|(near initialization)" } */
const double nok = nan (""); /* { dg-warning "(not a constant)|(near initialization)" } */
const double ok = __builtin_nan ("");

View File

@ -10,10 +10,10 @@ struct S
int b;
};
char c[(char *) &((struct S *) 0)->b - (char *) 0];
char d[(__SIZE_TYPE__) &((struct S *) 8)->b];
char e[sizeof (c) == __builtin_offsetof (struct S, b) ? 1 : -1];
char f[sizeof (d) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1];
char c[(char *) &((struct S *) 0)->b - (char *) 0]; /* { dg-error "variable-size" } */
char d[(__SIZE_TYPE__) &((struct S *) 8)->b]; /* { dg-error "variable-size" } */
char e[sizeof (c) == __builtin_offsetof (struct S, b) ? 1 : -1]; /* { dg-error "variably modified" } */
char f[sizeof (d) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1]; /* { dg-error "variably modified" } */
extern void bar (char *, char *);

View File

@ -1,4 +1,5 @@
/* PR middle-end/21781. */
/* { dg-do compile } */
/* { dg-options "-Wall" } */
int f[.0e200000000 == 0?1:-1];
int foo(void) { if (.0e200000000 == 0 ) return 1; }

View File

@ -16,7 +16,7 @@ const_f (filter_buffer_t *buf)
int i;
for (i = 0; i < 10; i++)
((float*) (&((sbuf_header_t *) ((buf) == (filter_buffer_t *)&(buf)->buf[0]))->buf[0]))[i] = val;
((float*) (&((sbuf_header_t *) (__PTRDIFF_TYPE__)((buf) == (filter_buffer_t *)&(buf)->buf[0]))->buf[0]))[i] = val;
}
/* { dg-final { cleanup-tree-dump "vect" } } */

View File

@ -0,0 +1,50 @@
/* Test for typeof evaluation: should be at the appropriate point in
the containing expression rather than just adding a statement. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do run } */
/* { dg-options "-std=gnu99" } */
extern void exit (int);
extern void abort (void);
void *p;
void
f1 (void)
{
int i = 0, j = -1, k = -1;
/* typeof applied to expression with cast. */
(j = ++i), (void)(typeof ((int (*)[(k = ++i)])p))p;
if (j != 1 || k != 2 || i != 2)
abort ();
}
void
f2 (void)
{
int i = 0, j = -1, k = -1;
/* typeof applied to type. */
(j = ++i), (void)(typeof (int (*)[(k = ++i)]))p;
if (j != 1 || k != 2 || i != 2)
abort ();
}
void
f3 (void)
{
int i = 0, j = -1, k = -1;
void *q;
/* typeof applied to expression with cast that is used. */
(j = ++i), (void)((typeof (1 + (int (*)[(k = ++i)])p))p);
if (j != 1 || k != 2 || i != 2)
abort ();
}
int
main (void)
{
f1 ();
f2 ();
f3 ();
exit (0);
}

View File

@ -0,0 +1,99 @@
/* Test for VLA size evaluation; see PR 35198. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do run } */
/* { dg-options "-std=c99" } */
extern void exit (int);
extern void abort (void);
int i;
void *p;
void
f1 (void *x, int j)
{
p = (int (*)[++i])x;
if (i != j)
abort ();
}
void
f1c (void *x, int j)
{
p = (int (*)[++i]){x};
if (i != j)
abort ();
}
void
f2 (void *x, int j)
{
x = (void *)(int (*)[++i])p;
if (i != j)
abort ();
}
void
f2c (void *x, int j)
{
x = (void *)(int (*)[++i]){p};
if (i != j)
abort ();
}
void
f3 (void *x, int j)
{
(void)(int (*)[++i])p;
if (i != j)
abort ();
}
void
f3c (void *x, int j)
{
(void)(int (*)[++i]){p};
if (i != j)
abort ();
}
void
f4 (void *x, int j)
{
(int (*)[++i])p;
(int (*)[++i])p;
if (i != j)
abort ();
}
void
f4c (void *x, int j)
{
(int (*)[++i]){p};
(int (*)[++i]){p};
if (i != j)
abort ();
}
void
f5c (void *x, int j, int k)
{
(++i, f3c (x, j), (int (*)[++i]){p});
if (i != k)
abort ();
}
int
main (void)
{
f1 (p, 1);
f2 (p, 2);
f3 (p, 3);
f4 (p, 5);
f1c (p, 6);
f2c (p, 7);
f3c (p, 8);
f4c (p, 10);
f5c (p, 12, 13);
exit (0);
}

View File

@ -0,0 +1,33 @@
/* Test for VLA size evaluation in va_arg. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do run } */
/* { dg-options "-std=gnu99" } */
#include <stdarg.h>
extern void exit (int);
extern void abort (void);
int a[10];
int i = 9;
void
f (int n, ...)
{
va_list ap;
void *p;
va_start (ap, n);
p = va_arg (ap, typeof (int (*)[++i]));
if (p != a)
abort ();
if (i != n)
abort ();
va_end (ap);
}
int
main (void)
{
f (10, &a);
exit (0);
}

View File

@ -0,0 +1,27 @@
/* Test for VLA size evaluation in sizeof typeof. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do run } */
/* { dg-options "-std=gnu99" } */
#include <stdarg.h>
extern void exit (int);
extern void abort (void);
char a[1];
void
f1 (void)
{
int i = 0;
int j = sizeof (typeof (*(++i, (char (*)[i])a)));
if (i != 1 || j != 1)
abort ();
}
int
main (void)
{
f1 ();
exit (0);
}

View File

@ -0,0 +1,70 @@
/* Test for modifying and taking addresses of compound literals whose
variably modified types involve typeof. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do run } */
/* { dg-options "-std=gnu99" } */
#include <stdarg.h>
extern void exit (int);
extern void abort (void);
int a[1];
void
f1 (void)
{
int i = 0;
int (**p)[1] = &(typeof (++i, (int (*)[i])a)){&a};
if (*p != &a)
abort ();
if (i != 1)
abort ();
}
void
f2 (void)
{
int i = 0;
(typeof (++i, (int (*)[i])a)){&a} = 0;
if (i != 1)
abort ();
}
void
f3 (void)
{
int i = 0;
(typeof (++i, (int (*)[i])a)){&a} += 1;
if (i != 1)
abort ();
}
void
f4 (void)
{
int i = 0;
--(typeof (++i, (int (*)[i])a)){&a + 1};
if (i != 1)
abort ();
}
void
f5 (void)
{
int i = 0;
(typeof (++i, (int (*)[i])a)){&a}++;
if (i != 1)
abort ();
}
int
main (void)
{
f1 ();
f2 ();
f3 ();
f4 ();
f5 ();
exit (0);
}