public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [4.5] C constant expressions, VLAs etc. fixes
@ 2008-10-24 17:20 Joseph S. Myers
  2008-10-24 17:59 ` Bruce Korb
  0 siblings, 1 reply; 2+ messages in thread
From: Joseph S. Myers @ 2008-10-24 17:20 UTC (permalink / raw)
  To: gcc-patches; +Cc: bkorb

[Bruce, note a fixincludes approval is requested below.]

This patch (for 4.5 Stage 1) fixes various issues related to constant
expressions and evaluation of variably modified types for C: bugs 456,
5675, 19976, 29116, 31871, 35198 and related issues tested by various
of the testcases added.

(It does not fix bug 32643, which is not a conformance issue since
implementations are neither required to accept nor required to reject
the code examples there; a patch something like the one in that bug
might be appropriate to fix that bug.  Nor does it fix bug 26374, a
target-specific conformance bug where valid constant expressions
involving IBM long double are not being accepted because of the
difficulty of folding arithmetic on this type.  Nor does it arrange
for casts to variably modified types to be accepted in static
initializers outside of functions, although it appears such usages may
be permitted by C99.)

In general, this patch follows the principle that integer constant
expressions are to be interpreted strictly and not extended (as per
the committee discussion in DR#312), while constant expressions in
initializers may be extended as long as the extensions do not violate
the Constraints applied to all constant expressions.  Thus, various
expressions that are not required to be accepted (and perhaps should
not be accepted) continue to be accepted in initializers.

In general, the semantics, where the standards are unclear or
self-contradictory, are guided by the formal models I previously
proposed <http://www.srcf.ucam.org/~jsm28/gcc/const-exprs-c90.txt>
<http://www.srcf.ucam.org/~jsm28/gcc/const-exprs-c99.txt>
<http://www.srcf.ucam.org/~jsm28/gcc/const-exprs-gnu.txt>.  However,
as noted above I have not tried to limit constant expressions in
initializers to the forms permitted by the models.  Furthermore, the
rules for __builtin_constant_p calls as conditional expression
condition in the implementation are more relaxed than those in the
formal model: the selected half of the conditional expression is fully
folded without regard to whether it is formally a constant expression,
since __builtin_constant_p tests a fully folded argument itself.

Although the semantics are guided by the formal models with sixteen
flags for each expression, the implementation does not try to add
those flags explicitly.  Instead, folding is delayed as far as
possible and then expressions are recursively examined (as part of
delayed folding) to determine whether they contain operands not
permitted in constant expressions.  Where problems might arise with
delayed recursive folding, a new C_MAYBE_CONST_EXPR is used to track
the constancy of contained folded expressions.  This tree code is also
used to deal with correct evaluation of expressions involved in
variably modified types.  (A new tree code is needed for this rather
than using COMPOUND_EXPR since you can have a compound literal, which
is an lvalue, whose type is defined in terms of typeof with argument
an expression of variably modified type, and that expression needs
evaluating before the compound literal.)

The C_MAYBE_CONST_EXPR code is eliminated in the delayed recursive
folding in c_fully_fold, so does not reach the gimplifier.  It is also
used to handle certain cases of integer constant expressions.  In
general, integer constant expressions and null pointer constants are
represented by INTEGER_CSTs, with folding for those expressions only
being carried out during parsing as at present.  (If such an
INTEGER_CST has TREE_OVERFLOW set, it is not however an integer
constant expression, and use where an integer constant expression is
required gets an error as at present.)

However, there can be subexpressions permitted within integer constant
expressions that do not get folded to INTEGER_CSTs - for example,
expressions containing a division by integer zero, that may occur in
an unevaluated part of an integer constant expression.  So the folding
during parsing can efficiently identify such expressions in the
unevaluated parts of ?:, || and && evaluation, and fold expressions
containing them to INTEGER_CSTs as appropriate, without quadratic
overhead examining subexpressions, a C_MAYBE_CONST_EXPR can also be
used to record that a contained expression has operands suitable for
an integer constant expression but is not such an expression itself,
and any expression with that property will be so represented.  Because
expressions that can occur in integer constant expressions are only
represented in one of these two ways (INTEGER_CST or
C_MAYBE_CONST_EXPR with this flag), this in turn means that where the
remaining folding produces an INTEGER_CST from something that cannot
occur in an integer constant expression (or is not a null pointer
constant, when it has pointer type), a NOP_EXPR can be used to wrap
the expression for as long as needed to ensure it is not allowed in an
integer constant expression.

c_fully_fold is intended to approximate the folding done during
parsing at present, although it may not always yield identical
results.  At present, there are still various "optimizations" done in
the C front end while the trees for expressions are built up, and some
cases where some folding still happens; such optimizations can be
incrementally moved out of the front end into fold (or other
optimizers) where they belong, and such folding during parsing
incrementally disabled, moving towards trees that more closely
correspond to the original source.

In addition, the front end does not logically need all the
transformations done by fold.  In principle, fold should act on GIMPLE
(so avoiding any present dependence on which subexpressions were
combined into larger expressions in the source program) with the only
folding done before gimplification being more limited folding required
for initializers.  With such a change, c_fully_fold would only need to
do the more limited folding.  If the C gimplification handled
C_MAYBE_CONST_EXPR, some calls to c_fully_fold could be eliminated
altogether; only those where the information about constancy is
required, in particular for static initializers, would need to remain.

However, c_fully_fold could also be thought of as a logical lowering
step, converting front-end-specific structures (which presently are
GENERIC plus the odd extra tree code) to GENERIC, with potentially
further transformations needed in future, and increases in the amount
of lowering involved (making datastructures correspond more closely to
the source for longer in the front end) might require this lowering
step everywhere even when folding isn't needed.

Bootstrapped with no regressions on i686-pc-linux-gnu.  I will put
this patch on a branch until 4.5 Stage 1 starts.  Are the fixincludes,
builtins.c and cp/typeck.c changes OK for 4.5?  (The fixincludes patch
addresses something I wrote for glibc's <tgmath.h> some time ago, that
was supposed to be an integer constant expression but isn't for
floating-point types after all, and so no longer works after this
patch; I'll send the fix upstream to glibc as well.  The builtins.c
change makes the results of folding a call after the CALL_EXPR was
created closer to those of folding at the time of building the
expression, and is needed to avoid bogus warnings about unused values
from built-in function calls.  The cp/typeck.c change allows
c_fully_fold to be called from c-common.c.)

fixincludes:
2008-10-24  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.

gcc:
2008-10-24  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_call_expr): Return a NOP_EXPR from folding
	rather than the contained expression.
	* c-common.c (c_save_expr): New.
	(c_common_truthvalue_conversion): Use c_save_expr.  Do not fold
	conditional expressions for C.
	* c-common.def (C_MAYBE_CONST_EXPR): New.
	* c-common.h (c_fully_fold, c_save_expr): 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.
	* c-typeck.c (c_fully_fold, c_fully_fold_internal,
	note_integer_operands): New functions.
	(decl_constant_value_for_broken_optimization): Rename to
	decl_constant_value_for_optimization:  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.
	(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.
	(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.
	(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.
	(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.
	(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/cp:
2008-10-24  Joseph Myers  <joseph@codesourcery.com>

	PR c/456
	PR c/5675
	PR c/19976
	PR c/29116
	PR c/31871
	PR c/35198
	* typeck.c (c_fully_fold): New.

gcc/testsuite:
2008-10-24  Joseph Myers  <joseph@codesourcery.com>

	PR c/456
	PR c/5675
	PR c/19976
	PR c/29116
	PR c/31871
	PR c/35198
	* gcc.dg/bconstp-2.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/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-11.c, gcc.dg/vla-12.c, gcc.dg/vla-13.c,
	gcc.dg/vla-14.c, gcc.dg/vla-15.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/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.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 141329)
+++ gcc/doc/extend.texi	(working copy)
@@ -662,6 +662,10 @@ A @code{typeof}-construct can be used an
 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
@@ -6571,9 +6575,8 @@ depending on the arguments' types.  For 
 
 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
@@ -6652,7 +6655,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.
 
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 141329)
+++ gcc/builtins.c	(working copy)
@@ -10723,7 +10723,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;
 	    }
Index: gcc/testsuite/gcc.dg/real-const-1.c
===================================================================
--- gcc/testsuite/gcc.dg/real-const-1.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/real-const-1.c	(working copy)
@@ -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; }
Index: gcc/testsuite/gcc.dg/c99-const-expr-9.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-9.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-9.c	(revision 0)
@@ -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])
+};
Index: gcc/testsuite/gcc.dg/overflow-warn-1.c
===================================================================
--- gcc/testsuite/gcc.dg/overflow-warn-1.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/overflow-warn-1.c	(working copy)
@@ -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-war
    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" } */
       ;
Index: gcc/testsuite/gcc.dg/c99-const-expr-11.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-11.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-11.c	(revision 0)
@@ -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;
+}
Index: gcc/testsuite/gcc.dg/overflow-warn-3.c
===================================================================
--- gcc/testsuite/gcc.dg/overflow-warn-3.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/overflow-warn-3.c	(working copy)
@@ -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 } */
       ;
     }
 }
Index: gcc/testsuite/gcc.dg/c90-const-expr-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-1.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c90-const-expr-1.c	(working copy)
@@ -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" } */
 }
Index: gcc/testsuite/gcc.dg/c99-const-expr-13.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-13.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-13.c	(revision 0)
@@ -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)];
+}
Index: gcc/testsuite/gcc.dg/gnu99-const-expr-2.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu99-const-expr-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gnu99-const-expr-2.c	(revision 0)
@@ -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 } */
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-3.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c90-const-expr-3.c	(working copy)
@@ -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" } */
 }
Index: gcc/testsuite/gcc.dg/vla-11.c
===================================================================
--- gcc/testsuite/gcc.dg/vla-11.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vla-11.c	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c99-const-expr-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-2.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c99-const-expr-2.c	(working copy)
@@ -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)));
 }
Index: gcc/testsuite/gcc.dg/vla-13.c
===================================================================
--- gcc/testsuite/gcc.dg/vla-13.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vla-13.c	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-10.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-10.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-10.c	(revision 0)
@@ -0,0 +1,22 @@
+/* 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" } */
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-7.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-7.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-7.c	(revision 0)
@@ -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 } */
Index: gcc/testsuite/gcc.dg/vla-15.c
===================================================================
--- gcc/testsuite/gcc.dg/vla-15.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vla-15.c	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-9.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-9.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-9.c	(revision 0)
@@ -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])
+};
Index: gcc/testsuite/gcc.dg/c99-const-expr-6.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-6.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-6.c	(revision 0)
@@ -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 + ((int) (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 + ((int) (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" } */
+      ;
+    }
+}
Index: gcc/testsuite/gcc.dg/gnu89-const-expr-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu89-const-expr-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gnu89-const-expr-1.c	(revision 0)
@@ -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" } */
+}
Index: gcc/testsuite/gcc.dg/c99-const-expr-8.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-8.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-8.c	(revision 0)
@@ -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.  */
+};
Index: gcc/testsuite/gcc.dg/c99-const-expr-10.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-10.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-10.c	(revision 0)
@@ -0,0 +1,22 @@
+/* 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" } */
+}
Index: gcc/testsuite/gcc.dg/c99-static-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-static-1.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c99-static-1.c	(working copy)
@@ -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).  */
Index: gcc/testsuite/gcc.dg/overflow-warn-2.c
===================================================================
--- gcc/testsuite/gcc.dg/overflow-warn-2.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/overflow-warn-2.c	(working copy)
@@ -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-war
    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;
 }
Index: gcc/testsuite/gcc.dg/c99-const-expr-12.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-12.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-12.c	(revision 0)
@@ -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" } */
+}
Index: gcc/testsuite/gcc.dg/overflow-warn-4.c
===================================================================
--- gcc/testsuite/gcc.dg/overflow-warn-4.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/overflow-warn-4.c	(working copy)
@@ -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 } */
       ;
     }
 }
Index: gcc/testsuite/gcc.dg/gnu99-const-expr-1.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu99-const-expr-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gnu99-const-expr-1.c	(revision 0)
@@ -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; }));
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-2.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c90-const-expr-2.c	(working copy)
@@ -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 ? 0 : (0, 0))); /* { dg-bogus "incompatible" "bogus null pointer constant" } */
 }
Index: gcc/testsuite/gcc.dg/gnu99-const-expr-3.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu99-const-expr-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gnu99-const-expr-3.c	(revision 0)
@@ -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;
+}
Index: gcc/testsuite/gcc.dg/pr14649-1.c
===================================================================
--- gcc/testsuite/gcc.dg/pr14649-1.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/pr14649-1.c	(working copy)
@@ -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);
 
Index: gcc/testsuite/gcc.dg/vla-12.c
===================================================================
--- gcc/testsuite/gcc.dg/vla-12.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vla-12.c	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-6.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-6.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-6.c	(revision 0)
@@ -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 + ((int) (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 + ((int) (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 + ((int) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */
+  switch (a)
+    {
+    case (n * 0 + 1): /* { dg-error "constant" } */
+      ;
+    }
+}
Index: gcc/testsuite/gcc.dg/c99-const-expr-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-3.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/c99-const-expr-3.c	(working copy)
@@ -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" } */
 }
Index: gcc/testsuite/gcc.dg/pr19984.c
===================================================================
--- gcc/testsuite/gcc.dg/pr19984.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/pr19984.c	(working copy)
@@ -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 ("");
 
Index: gcc/testsuite/gcc.dg/vla-14.c
===================================================================
--- gcc/testsuite/gcc.dg/vla-14.c	(revision 0)
+++ gcc/testsuite/gcc.dg/vla-14.c	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/bconstp-2.c
===================================================================
--- gcc/testsuite/gcc.dg/bconstp-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/bconstp-2.c	(revision 0)
@@ -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())
+};
Index: gcc/testsuite/gcc.dg/c90-const-expr-11.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-11.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-11.c	(revision 0)
@@ -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" } */
+}
Index: gcc/testsuite/gcc.dg/c90-const-expr-8.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-const-expr-8.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-const-expr-8.c	(revision 0)
@@ -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.  */
+};
Index: gcc/testsuite/gcc.dg/pr25682.c
===================================================================
--- gcc/testsuite/gcc.dg/pr25682.c	(revision 141329)
+++ gcc/testsuite/gcc.dg/pr25682.c	(working copy)
@@ -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 *);
 
Index: gcc/testsuite/gcc.dg/c99-const-expr-7.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-const-expr-7.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-const-expr-7.c	(revision 0)
@@ -0,0 +1,40 @@
+/* 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 } */
Index: gcc/testsuite/gcc.dg/gnu89-const-expr-2.c
===================================================================
--- gcc/testsuite/gcc.dg/gnu89-const-expr-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gnu89-const-expr-2.c	(revision 0)
@@ -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 } */
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 141329)
+++ gcc/cp/typeck.c	(working copy)
@@ -7391,3 +7391,13 @@ lvalue_or_else (const_tree ref, enum lva
 
   return win;
 }
+
+/* Dummy version of c_fully_fold for use in code shared by C and C++.
+   Return EXPR and ignore the other arguments.  */
+
+tree
+c_fully_fold (tree expr, bool in_init ATTRIBUTE_UNUSED,
+	      bool *maybe_const ATTRIBUTE_UNUSED)
+{
+  return expr;
+}
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h	(revision 141329)
+++ gcc/c-tree.h	(working copy)
@@ -145,6 +145,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
@@ -153,7 +157,9 @@ struct c_expr
   tree value;
   /* Record the original 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;
 };
@@ -189,6 +195,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.  */
@@ -226,6 +244,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
@@ -237,6 +258,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.  */
@@ -477,7 +501,7 @@ extern tree finish_struct (tree, tree, t
 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);
@@ -560,7 +584,7 @@ extern struct c_expr parser_build_unary_
 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);
@@ -576,7 +600,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);
-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);
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 141329)
+++ gcc/c-decl.c	(working copy)
@@ -410,8 +410,8 @@ static tree lookup_name_in_scope (tree, 
 static tree c_make_fname_decl (tree, int);
 static tree grokdeclarator (const struct c_declarator *,
 			    struct c_declspecs *,
-			    enum decl_context, bool, tree *, tree *,
-			    enum deprecated_states);
+			    enum decl_context, bool, tree *, tree *, tree *,
+			    bool *, enum deprecated_states);
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
 \f
@@ -3124,10 +3124,15 @@ add_flexible_array_elts_to_size (tree de
     }
 }
 \f
-/* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
+/* Decode a "typename", such as "int **", returning a ..._TYPE node.
+   Set *EXPR, if EXPR not NULL, to any expression to be evaluated
+   before the type name, and set *EXPR_CONST_OPERANDS, if
+   EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may
+   appear in a constant expression.  */
 
 tree
-groktypename (struct c_type_name *type_name)
+groktypename (struct c_type_name *type_name, tree *expr,
+	      bool *expr_const_operands)
 {
   tree type;
   tree attrs = type_name->specs->attrs;
@@ -3135,7 +3140,8 @@ groktypename (struct c_type_name *type_n
   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);
@@ -3164,6 +3170,7 @@ start_decl (struct c_declarator *declara
 {
   tree decl;
   tree tem;
+  tree expr = NULL_TREE;
   enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
 
   /* An object declared as __attribute__((deprecated)) suppresses
@@ -3172,11 +3179,14 @@ start_decl (struct c_declarator *declara
     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);
 
@@ -3664,7 +3674,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);
 
@@ -3681,7 +3691,7 @@ push_parm_decl (const struct c_parm *par
   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);
@@ -3712,10 +3722,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
@@ -3768,6 +3779,12 @@ build_compound_literal (tree type, tree 
       rest_of_decl_compilation (decl, 1, 0);
     }
 
+  if (non_const)
+    {
+      complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit);
+      C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1;
+    }
+
   return complit;
 }
 \f
@@ -3954,6 +3971,11 @@ warn_variable_length_array (const char *
    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.
 
@@ -3968,7 +3990,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;
@@ -3990,6 +4013,16 @@ grokdeclarator (const struct c_declarato
   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;
@@ -4302,6 +4335,11 @@ grokdeclarator (const struct c_declarato
 
 	    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);
@@ -4312,11 +4350,13 @@ grokdeclarator (const struct c_declarato
 		    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)
@@ -4324,6 +4364,13 @@ grokdeclarator (const struct c_declarato
 			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)
@@ -4336,11 +4383,11 @@ grokdeclarator (const struct c_declarato
 		    /* 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
@@ -4355,6 +4402,9 @@ grokdeclarator (const struct c_declarato
 		       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
@@ -4382,6 +4432,15 @@ grokdeclarator (const struct c_declarato
 
 		    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)
 	      {
@@ -5270,10 +5329,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
@@ -5440,7 +5504,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);
@@ -6097,7 +6161,7 @@ start_function (struct c_declspecs *decl
   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.  */
@@ -7110,10 +7174,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;
@@ -7635,7 +7701,18 @@ declspecs_add_type (struct c_declspecs *
       if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
 	specs->tag_defined_p = true;
       if (spec.kind == ctsk_typeof)
-	specs->typedef_p = true;
+	{
+	  specs->typedef_p = true;
+	  if (spec.expr)
+	    {
+	      if (specs->expr)
+		specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr),
+				      specs->expr, spec.expr);
+	      else
+		specs->expr = spec.expr;
+	      specs->expr_const_operands &= spec.expr_const_operands;
+	    }
+	}
       specs->type = type;
     }
 
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 141329)
+++ gcc/c-typeck.c	(working copy)
@@ -75,24 +75,25 @@ static int require_constant_value;
 static int require_constant_elements;
 
 static bool null_pointer_constant_p (const_tree);
+static tree c_fully_fold_internal (tree expr, bool, bool *, bool *);
 static tree qualify_type (tree, tree);
 static int tagged_types_tu_compatible_p (const_tree, const_tree);
 static int comp_target_types (tree, tree);
 static int function_types_compatible_p (const_tree, const_tree);
 static int type_lists_compatible_p (const_tree, const_tree);
-static tree decl_constant_value_for_broken_optimization (tree);
+static tree decl_constant_value_for_optimization (tree);
 static tree lookup_field (tree, tree);
 static int convert_arguments (int, tree *, tree, tree, tree, tree);
 static tree pointer_diff (tree, tree);
-static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
-				    int);
+static tree convert_for_assignment (tree, tree, enum impl_conv, bool,
+				    tree, tree, int);
 static tree valid_compound_expr_initializer (tree, tree);
 static void push_string (const char *);
 static void push_member_name (tree);
 static int spelling_length (void);
 static char *print_spelling (char *);
 static void warning_init (int, const char *);
-static tree digest_init (tree, tree, bool, int);
+static tree digest_init (tree, tree, bool, bool, int);
 static void output_init_element (tree, bool, tree, tree, int);
 static void output_pending_init_elements (int);
 static int set_designator (int);
@@ -123,6 +124,362 @@ null_pointer_constant_p (const_tree expr
 		  && VOID_TYPE_P (TREE_TYPE (type))
 		  && TYPE_QUALS (TREE_TYPE (type)) == TYPE_UNQUALIFIED)));
 }
+
+/* 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;
+
+  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);
+
+  /* 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;
+}
+
+/* EXPR may appear in an unevaluated part of an integer constant
+   expression, but not in an evaluated part.  Wrap it in a
+   C_MAYBE_CONST_EXPR.  */
+
+static tree
+note_integer_operands (tree expr)
+{
+  tree ret;
+  ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL_TREE, expr);
+  C_MAYBE_CONST_EXPR_INT_OPERANDS (ret) = 1;
+  return ret;
+}
+
 \f/* This is a cache to hold if two types are compatible or not.  */
 
 struct tagged_tu_seen_cache {
@@ -1556,27 +1913,27 @@ decl_constant_value (tree decl)
   return decl;
 }
 
-/* Return either DECL or its known constant value (if it has one), but
-   return DECL if pedantic or DECL has mode BLKmode.  This is for
-   bug-compatibility with the old behavior of decl_constant_value
-   (before GCC 3.0); every use of this function is a bug and it should
-   be removed before GCC 3.1.  It is not appropriate to use pedantic
-   in a way that affects optimization, and BLKmode is probably not the
-   right test for avoiding misoptimizations either.  */
+/* 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?  */
 
 static tree
-decl_constant_value_for_broken_optimization (tree decl)
+decl_constant_value_for_optimization (tree exp)
 {
   tree ret;
 
-  if (pedantic || DECL_MODE (decl) == BLKmode)
-    return decl;
+  if (!optimize
+      || TREE_CODE (exp) != VAR_DECL
+      || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+      || DECL_MODE (exp) == BLKmode)
+    return exp;
 
-  ret = decl_constant_value (decl);
+  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 != decl && TREE_STATIC (decl))
+  if (ret != exp && TREE_STATIC (exp))
     ret = unshare_expr (ret);
   return ret;
 }
@@ -1640,7 +1997,7 @@ function_to_pointer_conversion (tree exp
 
 /* Perform the default conversion of arrays and functions to pointers.
    Return the result of converting EXP.  For any other expression, just
-   return EXP after removing NOPs.  */
+   return EXP.  */
 
 struct c_expr
 default_function_array_conversion (struct c_expr exp)
@@ -1685,9 +2042,6 @@ default_function_array_conversion (struc
       exp.value = function_to_pointer_conversion (exp.value);
       break;
     default:
-      STRIP_TYPE_NOPS (exp.value);
-      if (TREE_NO_WARNING (orig_exp))
-	TREE_NO_WARNING (exp.value) = 1;
       break;
     }
 
@@ -1763,15 +2117,6 @@ default_conversion (tree exp)
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
 
-  /* Replace a nonvolatile const static variable with its value unless
-     it is an array, in which case we must be sure that taking the
-     address of the array produces consistent results.  */
-  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
-    {
-      exp = decl_constant_value_for_broken_optimization (exp);
-      type = TREE_TYPE (exp);
-    }
-
   /* Strip no-op conversions.  */
   orig_exp = exp;
   STRIP_TYPE_NOPS (exp);
@@ -2150,7 +2495,7 @@ build_array_ref (tree array, tree index,
 	       in an inline function.
 	       Hope it doesn't break something else.  */
 	    | TREE_THIS_VOLATILE (array));
-      ret = require_complete_type (fold (rval));
+      ret = require_complete_type (rval);
       protected_set_expr_location (ret, loc);
       return ret;
     }
@@ -2320,14 +2665,19 @@ c_expr_sizeof_expr (struct c_expr expr)
     }
   else
     {
-      ret.value = c_sizeof (TREE_TYPE (expr.value));
+      bool expr_const_operands = true;
+      tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+				       &expr_const_operands);
+      ret.value = c_sizeof (TREE_TYPE (folded_expr));
       ret.original_code = ERROR_MARK;
-      if (c_vla_type_p (TREE_TYPE (expr.value)))
+      if (c_vla_type_p (TREE_TYPE (folded_expr)))
 	{
 	  /* sizeof is evaluated when given a vla (C99 6.5.3.4p2).  */
-	  ret.value = build2 (COMPOUND_EXPR, TREE_TYPE (ret.value), expr.value, ret.value);
+	  ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+			      folded_expr, ret.value);
+	  C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
 	}
-      pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+      pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)));
     }
   return ret;
 }
@@ -2340,9 +2690,17 @@ c_expr_sizeof_type (struct c_type_name *
 {
   tree type;
   struct c_expr ret;
-  type = groktypename (t);
+  tree type_expr = NULL_TREE;
+  bool type_expr_const = true;
+  type = groktypename (t, &type_expr, &type_expr_const);
   ret.value = c_sizeof (type);
   ret.original_code = ERROR_MARK;
+  if (type_expr && c_vla_type_p (type))
+    {
+      ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+			  type_expr, ret.value);
+      C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+    }
   pop_maybe_used (type != error_mark_node
 		  ? C_TYPE_VARIABLE_SIZE (type) : false);
   return ret;
@@ -2435,7 +2793,8 @@ build_function_call (tree function, tree
 
 	  if (AGGREGATE_TYPE_P (return_type))
 	    rhs = build_compound_literal (return_type,
-					  build_constructor (return_type, 0));
+					  build_constructor (return_type, 0),
+					  false);
 	  else
 	    rhs = fold_convert (return_type, integer_zero_node);
 
@@ -2464,18 +2823,22 @@ build_function_call (tree function, tree
   check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
 			    TYPE_ARG_TYPES (fntype));
 
-  if (require_constant_value)
+  if (name != NULL_TREE
+      && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
     {
-      result = fold_build_call_array_initializer (TREE_TYPE (fntype),
-						  function, nargs, argarray);
-      if (TREE_CONSTANT (result)
-	  && (name == NULL_TREE
-	      || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
-	pedwarn_init (input_location, 0, "initializer element is not constant");
+      if (require_constant_value)
+	result = fold_build_call_array_initializer (TREE_TYPE (fntype),
+						    function, nargs, argarray);
+      else
+	result = fold_build_call_array (TREE_TYPE (fntype),
+					function, nargs, argarray);
+      if (TREE_CODE (result) == NOP_EXPR
+	  && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
+	STRIP_TYPE_NOPS (result);
     }
   else
-    result = fold_build_call_array (TREE_TYPE (fntype),
-				    function, nargs, argarray);
+    result = build_call_array (TREE_TYPE (fntype),
+			       function, nargs, argarray);
 
   if (VOID_TYPE_P (TREE_TYPE (result)))
     return result;
@@ -2535,6 +2898,7 @@ convert_arguments (int nargs, tree *arga
       tree rname = function;
       int argnum = parmnum + 1;
       const char *invalid_func_diag;
+      bool npc;
 
       if (type == void_type_node)
 	{
@@ -2548,6 +2912,8 @@ convert_arguments (int nargs, tree *arga
 	  argnum -= 2;
 	}
 
+      npc = null_pointer_constant_p (val);
+      val = c_fully_fold (val, false, NULL);
       STRIP_TYPE_NOPS (val);
 
       val = require_complete_type (val);
@@ -2688,7 +3054,7 @@ convert_arguments (int nargs, tree *arga
 		    }
 		}
 
-	      parmval = convert_for_assignment (type, val, ic_argpass,
+	      parmval = convert_for_assignment (type, val, ic_argpass, npc,
 						fundecl, function,
 						parmnum + 1);
 
@@ -2917,6 +3283,9 @@ build_unary_op (location_t location,
   tree ret = error_mark_node;
   int noconvert = flag;
   const char *invalid_op_diag;
+  bool int_operands;
+
+  int_operands = EXPR_INT_CONST_OPERANDS (xarg);
 
   if (code != ADDR_EXPR)
     arg = require_complete_type (arg);
@@ -3046,6 +3415,29 @@ build_unary_op (location_t location,
     case PREDECREMENT_EXPR:
     case POSTDECREMENT_EXPR:
 
+      if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+	{
+	  tree inner = build_unary_op (location, code,
+				       C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+	  if (inner == error_mark_node)
+	    return error_mark_node;
+	  ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+			C_MAYBE_CONST_EXPR_PRE (arg), inner);
+	  gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+	  C_MAYBE_CONST_EXPR_NON_CONST (ret) = 1;
+	  goto return_build_unary_op;
+	}
+
+      /* Complain about anything that is not a true lvalue.  */
+      if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
+				  || code == POSTINCREMENT_EXPR)
+				 ? lv_increment
+				 : lv_decrement)))
+	return error_mark_node;
+
+      /* Ensure the argument is fully folded inside any SAVE_EXPR.  */
+      arg = c_fully_fold (arg, false, NULL);
+
       /* Increment or decrement the real part of the value,
 	 and don't change the imaginary part.  */
       if (typecode == COMPLEX_TYPE)
@@ -3140,13 +3532,6 @@ build_unary_op (location_t location,
 	    inc = convert (argtype, inc);
 	  }
 
-	/* Complain about anything else that is not a true lvalue.  */
-	if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
-				    || code == POSTINCREMENT_EXPR)
-				   ? lv_increment
-				   : lv_decrement)))
-	  return error_mark_node;
-
 	/* Report a read-only lvalue.  */
 	if (TREE_READONLY (arg))
 	  {
@@ -3201,6 +3586,20 @@ build_unary_op (location_t location,
 	       && !lvalue_or_else (arg, lv_addressof))
 	return error_mark_node;
 
+      /* Move address operations inside C_MAYBE_CONST_EXPR to simplify
+	 folding later.  */
+      if (TREE_CODE (arg) == C_MAYBE_CONST_EXPR)
+	{
+	  tree inner = build_unary_op (location, code,
+				       C_MAYBE_CONST_EXPR_EXPR (arg), flag);
+	  ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+			C_MAYBE_CONST_EXPR_PRE (arg), inner);
+	  gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (arg));
+	  C_MAYBE_CONST_EXPR_NON_CONST (ret)
+	    = C_MAYBE_CONST_EXPR_NON_CONST (arg);
+	  goto return_build_unary_op;
+	}
+
       /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
       argtype = TREE_TYPE (arg);
 
@@ -3246,10 +3645,19 @@ build_unary_op (location_t location,
 
   if (argtype == 0)
     argtype = TREE_TYPE (arg);
-  ret = require_constant_value ? fold_build1_initializer (code, argtype, arg)
-			       : fold_build1 (code, argtype, arg);
+  if (TREE_CODE (arg) == INTEGER_CST)
+    ret = (require_constant_value
+	   ? fold_build1_initializer (code, argtype, arg)
+	   : fold_build1 (code, argtype, arg));
+  else
+    ret = build1 (code, argtype, arg);
  return_build_unary_op:
   gcc_assert (ret != error_mark_node);
+  if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret)
+      && !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg)))
+    ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+  else if (TREE_CODE (ret) != INTEGER_CST && int_operands)
+    ret = note_integer_operands (ret);
   protected_set_expr_location (ret, location);
   return ret;
 }
@@ -3270,6 +3678,9 @@ lvalue_p (const_tree ref)
     case COMPONENT_REF:
       return lvalue_p (TREE_OPERAND (ref, 0));
 
+    case C_MAYBE_CONST_EXPR:
+      return lvalue_p (TREE_OPERAND (ref, 1));
+
     case COMPOUND_LITERAL_EXPR:
     case STRING_CST:
       return 1;
@@ -3412,10 +3823,14 @@ c_mark_addressable (tree exp)
     }
 }
 \f
-/* Build and return a conditional expression IFEXP ? OP1 : OP2.  */
+/* Build and return a conditional expression IFEXP ? OP1 : OP2.  If
+   IFEXP_BCP then the condition is a call to __builtin_constant_p, and
+   if folded to an integer constant then the unselected half may
+   contain arbitrary operations not normally permitted in constant
+   expressions.  */
 
 tree
-build_conditional_expr (tree ifexp, tree op1, tree op2)
+build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
 {
   tree type1;
   tree type2;
@@ -3423,6 +3838,8 @@ build_conditional_expr (tree ifexp, tree
   enum tree_code code2;
   tree result_type = NULL;
   tree orig_op1 = op1, orig_op2 = op2;
+  bool int_const, op1_int_operands, op2_int_operands, int_operands;
+  tree ret;
 
   /* Promote both alternatives.  */
 
@@ -3582,7 +3999,40 @@ build_conditional_expr (tree ifexp, tree
   if (result_type != TREE_TYPE (op2))
     op2 = convert_and_check (result_type, op2);
 
-  return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+  op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
+  op2_int_operands = EXPR_INT_CONST_OPERANDS (orig_op2);
+  if (ifexp_bcp && ifexp == truthvalue_true_node)
+    {
+      op2_int_operands = true;
+      op1 = c_fully_fold (op1, require_constant_value, NULL);
+    }
+  if (ifexp_bcp && ifexp == truthvalue_false_node)
+    {
+      op1_int_operands = true;
+      op2 = c_fully_fold (op2, require_constant_value, NULL);
+    }
+  int_const = int_operands = (EXPR_INT_CONST_OPERANDS (ifexp)
+			      && op1_int_operands
+			      && op2_int_operands);
+  if (int_operands)
+    {
+      int_const = ((ifexp == truthvalue_true_node
+		    && TREE_CODE (orig_op1) == INTEGER_CST
+		    && !TREE_OVERFLOW (orig_op1))
+		   || (ifexp == truthvalue_false_node
+		       && TREE_CODE (orig_op2) == INTEGER_CST
+		       && !TREE_OVERFLOW (orig_op2)));
+    }
+  if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST))
+    ret = fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
+  else
+    {
+      ret = build3 (COND_EXPR, result_type, ifexp, op1, op2);
+      if (int_operands)
+	ret = note_integer_operands (ret);
+    }
+
+  return ret;
 }
 \f
 /* Return a compound expression that performs two expressions and
@@ -3591,6 +4041,8 @@ build_conditional_expr (tree ifexp, tree
 tree
 build_compound_expr (tree expr1, tree expr2)
 {
+  tree ret;
+
   if (!TREE_SIDE_EFFECTS (expr1))
     {
       /* The left-hand operand of a comma expression is like an expression
@@ -3621,7 +4073,14 @@ build_compound_expr (tree expr1, tree ex
   if (expr2 == error_mark_node)
     return error_mark_node;
 
-  return build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+  ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
+
+  if (flag_isoc99
+      && EXPR_INT_CONST_OPERANDS (expr1)
+      && EXPR_INT_CONST_OPERANDS (expr2))
+    ret = note_integer_operands (ret);
+
+  return ret;
 }
 
 /* Build an expression representing a cast to type TYPE of expression EXPR.  */
@@ -3686,7 +4145,7 @@ build_c_cast (tree type, tree expr)
 		   "ISO C forbids casts to union type");
 	  t = digest_init (type,
 			   build_constructor_single (type, field, value),
-			   true, 0);
+			   false, true, 0);
 	  TREE_CONSTANT (t) = TREE_CONSTANT (value);
 	  return t;
 	}
@@ -3810,7 +4269,7 @@ build_c_cast (tree type, tree expr)
       value = convert (type, value);
 
       /* Ignore any integer overflow caused by the cast.  */
-      if (TREE_CODE (value) == INTEGER_CST)
+      if (TREE_CODE (value) == INTEGER_CST && !FLOAT_TYPE_P (otype))
 	{
 	  if (CONSTANT_CLASS_P (ovalue) && TREE_OVERFLOW (ovalue))
 	    {
@@ -3833,6 +4292,20 @@ build_c_cast (tree type, tree expr)
   if (value == expr)
     value = non_lvalue (value);
 
+  /* Don't allow the results of casting to floating-point or complex
+     types be confused with actual constants, or casts involving
+     integer and pointer types other than direct integer-to-integer
+     and integer-to-pointer be confused with integer constant
+     expressions and null pointer constants.  */
+  if (TREE_CODE (value) == REAL_CST
+      || TREE_CODE (value) == COMPLEX_CST
+      || (TREE_CODE (value) == INTEGER_CST
+	  && !((TREE_CODE (expr) == INTEGER_CST
+		&& INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+	       || TREE_CODE (expr) == REAL_CST
+	       || TREE_CODE (expr) == COMPLEX_CST)))
+      value = build1 (NOP_EXPR, type, value);
+
   return value;
 }
 
@@ -3841,16 +4314,25 @@ tree
 c_cast_expr (struct c_type_name *type_name, tree expr)
 {
   tree type;
+  tree type_expr = NULL_TREE;
+  bool type_expr_const = true;
+  tree ret;
   int saved_wsp = warn_strict_prototypes;
 
   /* This avoids warnings about unprototyped casts on
      integers.  E.g. "#define SIG_DFL (void(*)())0".  */
   if (TREE_CODE (expr) == INTEGER_CST)
     warn_strict_prototypes = 0;
-  type = groktypename (type_name);
+  type = groktypename (type_name, &type_expr, &type_expr_const);
   warn_strict_prototypes = saved_wsp;
 
-  return build_c_cast (type, expr);
+  ret = build_c_cast (type, expr);
+  if (type_expr)
+    {
+      ret = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret), type_expr, ret);
+      C_MAYBE_CONST_EXPR_NON_CONST (ret) = !type_expr_const;
+    }
+  return ret;
 }
 \f
 /* Build an assignment expression of lvalue LHS from value RHS.
@@ -3868,6 +4350,7 @@ build_modify_expr (location_t location,
   tree newrhs;
   tree lhstype = TREE_TYPE (lhs);
   tree olhstype = lhstype;
+  bool npc;
 
   /* Types that aren't fully specified cannot be used in assignments.  */
   lhs = require_complete_type (lhs);
@@ -3879,15 +4362,28 @@ build_modify_expr (location_t location,
   if (!lvalue_or_else (lhs, lv_assign))
     return error_mark_node;
 
-  STRIP_TYPE_NOPS (rhs);
-
   newrhs = rhs;
 
+  if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
+    {
+      tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs),
+				      modifycode, rhs);
+      if (inner == error_mark_node)
+	return error_mark_node;
+      result = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (inner),
+		       C_MAYBE_CONST_EXPR_PRE (lhs), inner);
+      gcc_assert (!C_MAYBE_CONST_EXPR_INT_OPERANDS (lhs));
+      C_MAYBE_CONST_EXPR_NON_CONST (result) = 1;
+      protected_set_expr_location (result, location);
+      return result;
+    }
+
   /* If a binary op has been requested, combine the old LHS value with the RHS
      producing the value we should actually store into the LHS.  */
 
   if (modifycode != NOP_EXPR)
     {
+      lhs = c_fully_fold (lhs, false, NULL);
       lhs = stabilize_reference (lhs);
       newrhs = build_binary_op (location,
 				modifycode, lhs, rhs, 1);
@@ -3925,9 +4421,12 @@ build_modify_expr (location_t location,
       TREE_TYPE (lhs) = lhstype;
     }
 
-  /* Convert new value to destination type.  */
+  /* Convert new value to destination type.  Fold it first for the
+     sake of conversion warnings.  */
 
-  newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
+  npc = null_pointer_constant_p (newrhs);
+  newrhs = c_fully_fold (newrhs, false, NULL);
+  newrhs = convert_for_assignment (lhstype, newrhs, ic_assign, npc,
 				   NULL_TREE, NULL_TREE, 0);
   if (TREE_CODE (newrhs) == ERROR_MARK)
     return error_mark_node;
@@ -3957,14 +4456,15 @@ build_modify_expr (location_t location,
   if (olhstype == TREE_TYPE (result))
     return result;
 
-  result = convert_for_assignment (olhstype, result, ic_assign,
+  result = convert_for_assignment (olhstype, result, ic_assign, false,
 				   NULL_TREE, NULL_TREE, 0);
   protected_set_expr_location (result, location);
   return result;
 }
 \f
 /* Convert value RHS to type TYPE as preparation for an assignment
-   to an lvalue of type TYPE.
+   to an lvalue of type TYPE.  NULL_POINTER_CONSTANT says whether RHS
+   was a null pointer constant before any folding.
    The real work of conversion is done by `convert'.
    The purpose of this function is to generate error messages
    for assignments that are not allowed in C.
@@ -3976,6 +4476,7 @@ build_modify_expr (location_t location,
 
 static tree
 convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
+			bool null_pointer_constant,
 			tree fundecl, tree function, int parmnum)
 {
   enum tree_code codel = TREE_CODE (type);
@@ -4034,12 +4535,6 @@ convert_for_assignment (tree type, tree 
       }                                                                  \
   } while (0)
 
-  STRIP_TYPE_NOPS (rhs);
-
-  if (optimize && TREE_CODE (rhs) == VAR_DECL
-	   && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
-    rhs = decl_constant_value_for_broken_optimization (rhs);
-
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
 
@@ -4182,7 +4677,7 @@ convert_for_assignment (tree type, tree 
 	    }
 
 	  /* Can convert integer zero to any pointer type.  */
-	  if (null_pointer_constant_p (rhs))
+	  if (null_pointer_constant)
 	    {
 	      rhs = null_pointer_node;
 	      break;
@@ -4321,7 +4816,7 @@ convert_for_assignment (tree type, tree 
 	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
 		  ||
 		  (VOID_TYPE_P (ttr)
-		   && !null_pointer_constant_p (rhs)
+		   && !null_pointer_constant
 		   && TREE_CODE (ttl) == FUNCTION_TYPE)))
 	    WARN_FOR_ASSIGNMENT (input_location, OPT_pedantic,
 				 G_("ISO C forbids passing argument %d of "
@@ -4416,7 +4911,7 @@ convert_for_assignment (tree type, tree 
       /* An explicit constant 0 can convert to a pointer,
 	 or one that results from arithmetic, even including
 	 a cast to integer type.  */
-      if (!null_pointer_constant_p (rhs))
+      if (!null_pointer_constant)
 	WARN_FOR_ASSIGNMENT (input_location, 0,
 			     G_("passing argument %d of %qE makes "
 				"pointer from integer without a cast"),
@@ -4507,6 +5002,7 @@ void
 store_init_value (tree decl, tree init)
 {
   tree value, type;
+  bool npc = false;
 
   /* If variable's type was invalidly declared, just ignore it.  */
 
@@ -4516,7 +5012,9 @@ store_init_value (tree decl, tree init)
 
   /* Digest the specified initializer into an expression.  */
 
-  value = digest_init (type, init, true, TREE_STATIC (decl));
+  if (init)
+    npc = null_pointer_constant_p (init);
+  value = digest_init (type, init, npc, true, TREE_STATIC (decl));
 
   /* Store the expression if valid; else report error.  */
 
@@ -4747,6 +5245,8 @@ maybe_warn_string_init (tree type, struc
 /* Digest the parser output INIT as an initializer for type TYPE.
    Return a C expression of type TYPE to represent the initial value.
 
+   NULL_POINTER_CONSTANT is true if INIT is a null pointer constant.
+
    If INIT is a string constant, STRICT_STRING is true if it is
    unparenthesized or we should not warn here for it being parenthesized.
    For other types of INIT, STRICT_STRING is not used.
@@ -4755,10 +5255,12 @@ maybe_warn_string_init (tree type, struc
    elements are seen.  */
 
 static tree
-digest_init (tree type, tree init, bool strict_string, int require_constant)
+digest_init (tree type, tree init, bool null_pointer_constant,
+	     bool strict_string, int require_constant)
 {
   enum tree_code code = TREE_CODE (type);
   tree inside_init = init;
+  bool maybe_const = true;
 
   if (type == error_mark_node
       || !init
@@ -4768,7 +5270,8 @@ digest_init (tree type, tree init, bool 
 
   STRIP_TYPE_NOPS (inside_init);
 
-  inside_init = fold (inside_init);
+  inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
+  inside_init = decl_constant_value_for_optimization (inside_init);
 
   /* Initialization of an array of chars from a string constant
      optionally enclosed in braces.  */
@@ -4938,9 +5441,6 @@ digest_init (tree type, tree init, bool 
 	  return error_mark_node;
 	}
 
-      if (optimize && TREE_CODE (inside_init) == VAR_DECL)
-	inside_init = decl_constant_value_for_broken_optimization (inside_init);
-
       /* Compound expressions can only occur here if -pedantic or
 	 -pedantic-errors is specified.  In the later case, we always want
 	 an error.  In the former case, we simply want a warning.  */
@@ -4965,11 +5465,15 @@ digest_init (tree type, tree init, bool 
 	  error_init ("initializer element is not constant");
 	  inside_init = error_mark_node;
 	}
+      else if (require_constant && !maybe_const)
+	pedwarn_init (input_location, 0,
+		      "initializer element is not a constant expression");
 
       /* Added to enable additional -Wmissing-format-attribute warnings.  */
       if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
-	inside_init = convert_for_assignment (type, inside_init, ic_init, NULL_TREE,
-					      NULL_TREE, 0);
+	inside_init = convert_for_assignment (type, inside_init, ic_init,
+					      null_pointer_constant,
+					      NULL_TREE, NULL_TREE, 0);
       return inside_init;
     }
 
@@ -4982,9 +5486,10 @@ digest_init (tree type, tree init, bool 
       if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
 	  && (TREE_CODE (init) == STRING_CST
 	      || TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
-	init = array_to_pointer_conversion (init);
+	inside_init = init = array_to_pointer_conversion (init);
       inside_init
-	= convert_for_assignment (type, init, ic_init,
+	= convert_for_assignment (type, inside_init, ic_init,
+				  null_pointer_constant,
 				  NULL_TREE, NULL_TREE, 0);
 
       /* Check to see if we have already given an error message.  */
@@ -5002,6 +5507,9 @@ digest_init (tree type, tree init, bool 
 	  error_init ("initializer element is not computable at load time");
 	  inside_init = error_mark_node;
 	}
+      else if (require_constant && !maybe_const)
+	pedwarn_init (input_location, 0,
+		      "initializer element is not a constant expression");
 
       return inside_init;
     }
@@ -5061,6 +5569,10 @@ static int constructor_constant;
 /* 1 if so far this constructor's elements are all valid address constants.  */
 static int constructor_simple;
 
+/* 1 if this constructor has an element that cannot be part of a
+   constant expression.  */
+static int constructor_nonconst;
+
 /* 1 if this constructor is erroneous so far.  */
 static int constructor_erroneous;
 
@@ -5130,6 +5642,7 @@ struct constructor_stack
   struct constructor_range_stack *range_stack;
   char constant;
   char simple;
+  char nonconst;
   char implicit;
   char erroneous;
   char outer;
@@ -5293,6 +5806,7 @@ really_start_incremental_init (tree type
   p->elements = constructor_elements;
   p->constant = constructor_constant;
   p->simple = constructor_simple;
+  p->nonconst = constructor_nonconst;
   p->erroneous = constructor_erroneous;
   p->pending_elts = constructor_pending_elts;
   p->depth = constructor_depth;
@@ -5308,6 +5822,7 @@ really_start_incremental_init (tree type
 
   constructor_constant = 1;
   constructor_simple = 1;
+  constructor_nonconst = 0;
   constructor_depth = SPELLING_DEPTH ();
   constructor_elements = 0;
   constructor_pending_elts = 0;
@@ -5434,6 +5949,7 @@ push_init_level (int implicit)
   p->elements = constructor_elements;
   p->constant = constructor_constant;
   p->simple = constructor_simple;
+  p->nonconst = constructor_nonconst;
   p->erroneous = constructor_erroneous;
   p->pending_elts = constructor_pending_elts;
   p->depth = constructor_depth;
@@ -5449,6 +5965,7 @@ push_init_level (int implicit)
 
   constructor_constant = 1;
   constructor_simple = 1;
+  constructor_nonconst = 0;
   constructor_depth = SPELLING_DEPTH ();
   constructor_elements = 0;
   constructor_incremental = 1;
@@ -5498,6 +6015,7 @@ push_init_level (int implicit)
     {
       constructor_constant = TREE_CONSTANT (value);
       constructor_simple = TREE_STATIC (value);
+      constructor_nonconst = CONSTRUCTOR_NON_CONST (value);
       constructor_elements = CONSTRUCTOR_ELTS (value);
       if (!VEC_empty (constructor_elt, constructor_elements)
 	  && (TREE_CODE (constructor_type) == RECORD_TYPE
@@ -5702,9 +6220,19 @@ pop_init_level (int implicit)
 	    TREE_CONSTANT (ret.value) = 1;
 	  if (constructor_constant && constructor_simple)
 	    TREE_STATIC (ret.value) = 1;
+	  if (constructor_nonconst)
+	    CONSTRUCTOR_NON_CONST (ret.value) = 1;
 	}
     }
 
+  if (ret.value && TREE_CODE (ret.value) != CONSTRUCTOR)
+    {
+      if (constructor_nonconst)
+	ret.original_code = C_MAYBE_CONST_EXPR;
+      else if (ret.original_code == C_MAYBE_CONST_EXPR)
+	ret.original_code = ERROR_MARK;
+    }
+
   constructor_type = p->type;
   constructor_fields = p->fields;
   constructor_index = p->index;
@@ -5715,6 +6243,7 @@ pop_init_level (int implicit)
   constructor_elements = p->elements;
   constructor_constant = p->constant;
   constructor_simple = p->simple;
+  constructor_nonconst = p->nonconst;
   constructor_erroneous = p->erroneous;
   constructor_incremental = p->incremental;
   constructor_designated = p->designated;
@@ -5849,6 +6378,9 @@ set_init_index (tree first, tree last)
     error_init ("array index in initializer exceeds array bounds");
   else
     {
+      constant_expression_warning (first);
+      if (last)
+	constant_expression_warning (last);
       constructor_index = convert (bitsizetype, first);
 
       if (last)
@@ -6321,6 +6853,8 @@ output_init_element (tree value, bool st
 		     int pending)
 {
   constructor_elt *celt;
+  bool maybe_const = true;
+  bool npc;
 
   if (type == error_mark_node || value == error_mark_node)
     {
@@ -6347,6 +6881,9 @@ output_init_element (tree value, bool st
       value = DECL_INITIAL (decl);
     }
 
+  npc = null_pointer_constant_p (value);
+  value = c_fully_fold (value, require_constant_value, &maybe_const);
+
   if (value == error_mark_node)
     constructor_erroneous = 1;
   else if (!TREE_CONSTANT (value))
@@ -6357,6 +6894,8 @@ output_init_element (tree value, bool st
 	       && DECL_C_BIT_FIELD (field)
 	       && TREE_CODE (value) != INTEGER_CST))
     constructor_simple = 0;
+  if (!maybe_const)
+    constructor_nonconst = 1;
 
   if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
     {
@@ -6369,6 +6908,10 @@ output_init_element (tree value, bool st
 	pedwarn (input_location, 0,
 		 "initializer element is not computable at load time");
     }
+  else if (!maybe_const
+	   && (require_constant_value || require_constant_elements))
+    pedwarn_init (input_location, 0,
+		  "initializer element is not a constant expression");
 
   /* If this field is empty (and not at the end of structure),
      don't do anything other than checking the initializer.  */
@@ -6380,12 +6923,15 @@ output_init_element (tree value, bool st
 		  || TREE_CHAIN (field)))))
     return;
 
-  value = digest_init (type, value, strict_string, require_constant_value);
+  value = digest_init (type, value, npc, strict_string,
+		       require_constant_value);
   if (value == error_mark_node)
     {
       constructor_erroneous = 1;
       return;
     }
+  if (require_constant_value || require_constant_elements)
+    constant_expression_warning (value);
 
   /* If this element doesn't come next in sequence,
      put it on constructor_pending_elts.  */
@@ -6682,7 +7228,7 @@ process_init_element (struct c_expr valu
       if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
 	  || !require_constant_value
 	  || flag_isoc99)
-	value.value = save_expr (value.value);
+	value.value = c_save_expr (value.value);
     }
 
   while (1)
@@ -7155,6 +7701,7 @@ tree
 c_finish_goto_ptr (tree expr)
 {
   pedwarn (input_location, OPT_pedantic, "ISO C forbids %<goto *expr;%>");
+  expr = c_fully_fold (expr, false, NULL);
   expr = convert (ptr_type_node, expr);
   return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
 }
@@ -7167,10 +7714,17 @@ c_finish_return (tree retval)
 {
   tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt;
   bool no_warning = false;
+  bool npc = false;
 
   if (TREE_THIS_VOLATILE (current_function_decl))
     warning (0, "function declared %<noreturn%> has a %<return%> statement");
 
+  if (retval)
+    {
+      npc = null_pointer_constant_p (retval);
+      retval = c_fully_fold (retval, false, NULL);
+    }
+
   if (!retval)
     {
       current_function_returns_null = 1;
@@ -7195,7 +7749,7 @@ c_finish_return (tree retval)
     }
   else
     {
-      tree t = convert_for_assignment (valtype, retval, ic_return,
+      tree t = convert_for_assignment (valtype, retval, ic_return, npc,
 				       NULL_TREE, NULL_TREE, 0);
       tree res = DECL_RESULT (current_function_decl);
       tree inner;
@@ -7337,6 +7891,7 @@ c_start_case (tree exp)
 	    warning (OPT_Wtraditional, "%<long%> switch expression not "
 		     "converted to %<int%> in ISO C");
 
+	  exp = c_fully_fold (exp, false, NULL);
 	  exp = default_conversion (exp);
 
 	  if (warn_sequence_point)
@@ -7630,6 +8185,8 @@ c_process_expr_stmt (tree expr)
   if (!expr)
     return NULL_TREE;
 
+  expr = c_fully_fold (expr, false, NULL);
+
   if (warn_sequence_point)
     verify_sequence_points (expr);
 
@@ -7785,10 +8342,13 @@ c_finish_stmt_expr (tree body)
       || (last == BIND_EXPR_BODY (body)
 	  && BIND_EXPR_VARS (body) == NULL))
     {
+      /* Even if this looks constant, do not allow it in a constant
+	 expression.  */
+      last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
+      C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
       /* Do not warn if the return value of a statement expression is
 	 unused.  */
-      if (CAN_HAVE_LOCATION_P (last))
-	TREE_NO_WARNING (last) = 1;
+      TREE_NO_WARNING (last) = 1;
       return last;
     }
 
@@ -7980,6 +8540,7 @@ build_binary_op (location_t location, en
   tree op0, op1;
   tree ret = error_mark_node;
   const char *invalid_op_diag;
+  bool int_const, int_const_or_overflow, int_operands;
 
   /* Expression code to give to the expression when it is built.
      Normally this is CODE, which is what the caller asked for,
@@ -8029,6 +8590,19 @@ build_binary_op (location_t location, en
   if (location == UNKNOWN_LOCATION)
     location = input_location;
 
+  int_operands = (EXPR_INT_CONST_OPERANDS (orig_op0)
+		  && EXPR_INT_CONST_OPERANDS (orig_op1));
+  if (int_operands)
+    {
+      int_const_or_overflow = (TREE_CODE (orig_op0) == INTEGER_CST
+			       && TREE_CODE (orig_op1) == INTEGER_CST);
+      int_const = (int_const_or_overflow
+		   && !TREE_OVERFLOW (orig_op0)
+		   && !TREE_OVERFLOW (orig_op1));
+    }
+  else
+    int_const = int_const_or_overflow = false;
+
   if (convert_p)
     {
       op0 = default_conversion (orig_op0);
@@ -8195,6 +8769,28 @@ build_binary_op (location_t location, en
 	  op1 = c_common_truthvalue_conversion (location, op1);
 	  converted = 1;
 	}
+      if (code == TRUTH_ANDIF_EXPR)
+	{
+	  int_const_or_overflow = (int_operands
+				   && TREE_CODE (orig_op0) == INTEGER_CST
+				   && (op0 == truthvalue_false_node
+				       || TREE_CODE (orig_op1) == INTEGER_CST));
+	  int_const = (int_const_or_overflow
+		       && !TREE_OVERFLOW (orig_op0)
+		       && (op0 == truthvalue_false_node
+			   || !TREE_OVERFLOW (orig_op1)));
+	}
+      else if (code == TRUTH_ORIF_EXPR)
+	{
+	  int_const_or_overflow = (int_operands
+				   && TREE_CODE (orig_op0) == INTEGER_CST
+				   && (op0 == truthvalue_true_node
+				       || TREE_CODE (orig_op1) == INTEGER_CST));
+	  int_const = (int_const_or_overflow
+		       && !TREE_OVERFLOW (orig_op0)
+		       && (op0 == truthvalue_true_node
+			   || !TREE_OVERFLOW (orig_op1)));
+	}
       break;
 
       /* Shift operations: result has same type as first operand;
@@ -8205,17 +8801,25 @@ build_binary_op (location_t location, en
       if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
-	  if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_sgn (op1) < 0)
-		warning (0, "right shift count is negative");
+		{
+		  int_const = false;
+		  if (skip_evaluation == 0)
+		    warning (0, "right shift count is negative");
+		}
 	      else
 		{
 		  if (!integer_zerop (op1))
 		    short_shift = 1;
 
 		  if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-		    warning (0, "right shift count >= width of type");
+		    {
+		      int_const = false;
+		      if (skip_evaluation == 0)
+			warning (0, "right shift count >= width of type");
+		    }
 		}
 	    }
 
@@ -8234,13 +8838,21 @@ build_binary_op (location_t location, en
       if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
 	  && code1 == INTEGER_TYPE)
 	{
-	  if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
+	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_sgn (op1) < 0)
-		warning (0, "left shift count is negative");
+		{
+		  int_const = false;
+		  if (skip_evaluation == 0)
+		    warning (0, "left shift count is negative");
+		}
 
 	      else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-		warning (0, "left shift count >= width of type");
+		{
+		  int_const = false;
+		  if (skip_evaluation == 0)
+		    warning (0, "left shift count >= width of type");
+		}
 	    }
 
 	  /* Use the type of the value to be shifted.  */
@@ -8530,16 +9142,23 @@ build_binary_op (location_t location, en
     build_type = result_type;
 
   /* Treat expressions in initializers specially as they can't trap.  */
-  ret = require_constant_value ? fold_build2_initializer (resultcode,
-							  build_type,
-							  op0, op1)
-			       : fold_build2 (resultcode, build_type,
-					      op0, op1);
+  if (int_const_or_overflow)
+    ret = (require_constant_value
+	   ? fold_build2_initializer (resultcode, build_type, op0, op1)
+	   : fold_build2 (resultcode, build_type, op0, op1));
+  else
+    ret = build2 (resultcode, build_type, op0, op1);
   if (final_type != 0)
     ret = convert (final_type, ret);
 
  return_build_binary_op:
   gcc_assert (ret != error_mark_node);
+  if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret) && !int_const)
+    ret = (int_operands
+	   ? note_integer_operands (ret)
+	   : build1 (NOP_EXPR, TREE_TYPE (ret), ret));
+  else if (TREE_CODE (ret) != INTEGER_CST && int_operands)
+    ret = note_integer_operands (ret);
   protected_set_expr_location (ret, location);
   return ret;
 }
@@ -8551,6 +9170,8 @@ build_binary_op (location_t location, en
 tree
 c_objc_common_truthvalue_conversion (location_t location, tree expr)
 {
+  bool int_const, int_operands;
+
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case ARRAY_TYPE:
@@ -8572,9 +9193,23 @@ c_objc_common_truthvalue_conversion (loc
       break;
     }
 
+  int_const = (TREE_CODE (expr) == INTEGER_CST && !TREE_OVERFLOW (expr));
+  int_operands = EXPR_INT_CONST_OPERANDS (expr);
+
   /* ??? Should we also give an error for void and vectors rather than
      leaving those to give errors later?  */
-  return c_common_truthvalue_conversion (location, expr);
+  expr = c_common_truthvalue_conversion (location, expr);
+
+  if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)
+    {
+      if (TREE_OVERFLOW (expr))
+	return expr;
+      else
+	return note_integer_operands (expr);
+    }
+  if (TREE_CODE (expr) == INTEGER_CST && !int_const)
+    return build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+  return expr;
 }
 \f
 
Index: gcc/c-convert.c
===================================================================
--- gcc/c-convert.c	(revision 141329)
+++ gcc/c-convert.c	(working copy)
@@ -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)
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 141329)
+++ gcc/c-common.c	(working copy)
@@ -3331,6 +3331,27 @@ pointer_int_sum (enum tree_code resultco
   return ret;
 }
 \f
+/* Wrap a SAVE_EXPR around EXPR, if appropriate.  Like save_expr, but
+   for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR
+   around the SAVE_EXPR if needed so that c_fully_fold does not need
+   to look inside SAVE_EXPRs.  */
+
+tree
+c_save_expr (tree expr)
+{
+  bool maybe_const = true;
+  if (c_dialect_cxx ())
+    return save_expr (expr);
+  expr = c_fully_fold (expr, false, &maybe_const);
+  expr = save_expr (expr);
+  if (!maybe_const)
+    {
+      expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr);
+      C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1;
+    }
+  return expr;
+}
+
 /* Return whether EXPR is a declaration whose address can never be
    NULL.  */
 
@@ -3473,12 +3494,23 @@ c_common_truthvalue_conversion (location
 
     case COND_EXPR:
       /* Distribute the conversion into the arms of a COND_EXPR.  */
-      return fold_build3 (COND_EXPR, truthvalue_type_node,
-		TREE_OPERAND (expr, 0),
-		c_common_truthvalue_conversion (location,
-						TREE_OPERAND (expr, 1)),
-		c_common_truthvalue_conversion (location,
-						TREE_OPERAND (expr, 2)));
+      if (c_dialect_cxx ())
+	return fold_build3 (COND_EXPR, truthvalue_type_node,
+			    TREE_OPERAND (expr, 0),
+			    c_common_truthvalue_conversion (location,
+							    TREE_OPERAND (expr,
+									  1)),
+			    c_common_truthvalue_conversion (location,
+							    TREE_OPERAND (expr,
+									  2)));
+      else
+	/* Folding will happen later for C.  */
+	return build3 (COND_EXPR, truthvalue_type_node,
+		       TREE_OPERAND (expr, 0),
+		       c_common_truthvalue_conversion (location,
+						       TREE_OPERAND (expr, 1)),
+		       c_common_truthvalue_conversion (location,
+						       TREE_OPERAND (expr, 2)));
 
     CASE_CONVERT:
       /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
@@ -3509,7 +3541,7 @@ c_common_truthvalue_conversion (location
 
   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)
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h	(revision 141329)
+++ gcc/c-common.h	(working copy)
@@ -29,8 +29,10 @@ along with GCC; see the file COPYING3.  
    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
@@ -714,6 +716,8 @@ 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 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 +803,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)
Index: gcc/c-common.def
===================================================================
--- gcc/c-common.def	(revision 141329)
+++ gcc/c-common.def	(working copy)
@@ -31,6 +31,21 @@ along with GCC; see the file COPYING3.  
    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
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 141329)
+++ gcc/c-parser.c	(working copy)
@@ -915,7 +915,7 @@ static struct c_expr c_parser_postfix_ex
 								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, st
 	      /* 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, st
 	      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, st
 	  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, st
 	    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 *parse
       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 *parse
       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_pa
       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_pa
       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 *par
   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 *par
       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 *par
 	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 %<)%>");
@@ -2856,7 +2862,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
@@ -2864,7 +2871,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))
@@ -3739,8 +3746,9 @@ c_parser_statement_after_labels (c_parse
 	    }
 	  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;
@@ -3801,8 +3809,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);
@@ -4295,6 +4304,7 @@ c_parser_asm_operands (c_parser *parser,
       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 %<)%>"))
 	{
@@ -4449,7 +4459,7 @@ c_parser_conditional_expression (c_parse
       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;
     }
@@ -4473,7 +4483,9 @@ c_parser_conditional_expression (c_parse
   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;
 }
@@ -5010,7 +5022,7 @@ c_parser_alignof_expression (c_parser *p
       /* 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;
     }
@@ -5187,7 +5199,8 @@ c_parser_postfix_expression (c_parser *p
 	  expr = c_parser_expression (parser);
 	  if (TREE_CODE (expr.value) == MODIFY_EXPR)
 	    TREE_NO_WARNING (expr.value) = 1;
-	  expr.original_code = ERROR_MARK;
+	  if (expr.original_code != C_MAYBE_CONST_EXPR)
+	    expr.original_code = ERROR_MARK;
 	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
 				     "expected %<)%>");
 	}
@@ -5213,6 +5226,7 @@ c_parser_postfix_expression (c_parser *p
 	      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);
@@ -5230,7 +5244,17 @@ c_parser_postfix_expression (c_parser *p
 	    }
 	  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;
@@ -5257,7 +5281,7 @@ c_parser_postfix_expression (c_parser *p
 	      break;
 	    }
 	  {
-	    tree type = groktypename (t1);
+	    tree type = groktypename (t1, NULL, NULL);
 	    tree offsetof_ref;
 	    if (type == error_mark_node)
 	      offsetof_ref = error_mark_node;
@@ -5295,6 +5319,7 @@ c_parser_postfix_expression (c_parser *p
 			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);
@@ -5341,10 +5366,12 @@ c_parser_postfix_expression (c_parser *p
 	    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;
@@ -5382,8 +5409,8 @@ c_parser_postfix_expression (c_parser *p
 	  {
 	    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)
@@ -5455,7 +5482,7 @@ c_parser_postfix_expression (c_parser *p
 	  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;
 	  }
@@ -5505,10 +5532,13 @@ c_parser_postfix_expression_after_paren_
 {
   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))
     {
@@ -5521,8 +5551,26 @@ c_parser_postfix_expression_after_paren_
 
   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);
 }
 
@@ -5533,6 +5581,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)
@@ -5555,11 +5604,17 @@ c_parser_postfix_expression_after_primar
 	  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;
           if (warn_disallowed_functions)
             warn_if_disallowed_function_p (expr.value);
 	  break;
@@ -5659,7 +5714,7 @@ c_parser_expression_conv (c_parser *pars
 }
 
 /* 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
@@ -5667,13 +5722,15 @@ c_parser_expression_conv (c_parser *pars
 */
 
 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))
     {
@@ -5681,6 +5738,7 @@ c_parser_expr_list (c_parser *parser, bo
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
 	expr = default_function_array_conversion (expr);
+      expr.value = c_fully_fold (expr.value, false, NULL);
       cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
     }
   return ret;
@@ -6266,7 +6324,7 @@ c_parser_objc_type_name (c_parser *parse
   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);
 }
 
@@ -6372,6 +6430,7 @@ c_parser_objc_synchronized_statement (c_
   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
@@ -6507,7 +6566,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.
@@ -6555,7 +6614,7 @@ c_parser_objc_message_args (c_parser *pa
 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
@@ -7031,6 +7090,7 @@ c_parser_omp_clause_num_threads (c_parse
     {
       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 %<)%>");
 
@@ -7209,6 +7269,7 @@ c_parser_omp_clause_schedule (c_parser *
 
       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 "
@@ -7408,6 +7469,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:
@@ -7469,6 +7531,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);
@@ -7631,6 +7694,7 @@ c_parser_omp_for_loop (c_parser *parser,
 
 	  cond = c_parser_expression_conv (parser).value;
 	  cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+	  cond = c_fully_fold (cond, false, NULL);
 	  protected_set_expr_location (cond, cond_loc);
 	}
       c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
Index: fixincludes/fixincl.x
===================================================================
--- fixincludes/fixincl.x	(revision 141329)
+++ fixincludes/fixincl.x	(working copy)
@@ -2,11 +2,11 @@
  * 
  * DO NOT EDIT THIS FILE   (fixincl.x)
  * 
- * It has been AutoGen-ed  Saturday September  6, 2008 at 11:42:15 AM PDT
+ * It has been AutoGen-ed  Friday October 24, 2008 at 11:44:56 AM UTC
  * From the definitions    inclhack.def
  * and the template file   fixincl
  */
-/* DO NOT SVN-MERGE THIS FILE, EITHER Sat Sep  6 11:42:15 PDT 2008
+/* DO NOT SVN-MERGE THIS FILE, EITHER Fri Oct 24 11:44:56 UTC 2008
  *
  * 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.
  *
@@ -2265,6 +2265,48 @@ s/{ { 0, } }/{ { 0, 0, 0, 0, 0, 0 } }/\n
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
+ *  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.*__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)",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
  *  Description of Gnu_Types fix
  */
 tSCC zGnu_TypesName[] =
@@ -7182,9 +7224,9 @@ static const char* apzX11_SprintfPatch[]
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          223
+#define REGEX_COUNT          225
 #define MACH_LIST_SIZE_LIMIT 181
-#define FIX_COUNT            177
+#define FIX_COUNT            178
 
 /*
  *  Enumerate the fixes
@@ -7244,6 +7286,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,
@@ -7640,6 +7683,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,
Index: fixincludes/tests/base/tgmath.h
===================================================================
--- fixincludes/tests/base/tgmath.h	(revision 0)
+++ fixincludes/tests/base/tgmath.h	(revision 0)
@@ -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)
+#endif  /* GLIBC_TGMATH_CHECK */
Index: fixincludes/inclhack.def
===================================================================
--- fixincludes/inclhack.def	(revision 141329)
+++ fixincludes/inclhack.def	(working copy)
@@ -1289,6 +1289,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.*__builtin_classify_type";
+    c_fix     = format;
+    c_fix_arg = "(__builtin_classify_type ((type) 0) == 8 || __builtin_classify_type ((type) 0) == 9)";
+    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.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 2+ messages in thread

* RE: [4.5] C constant expressions, VLAs etc. fixes
  2008-10-24 17:20 [4.5] C constant expressions, VLAs etc. fixes Joseph S. Myers
@ 2008-10-24 17:59 ` Bruce Korb
  0 siblings, 0 replies; 2+ messages in thread
From: Bruce Korb @ 2008-10-24 17:59 UTC (permalink / raw)
  To: gcc-patches, Joseph S. Myers

Hi Joseph,

Fixincludes stuff looks good to me.  A tiny nit:

+    select    = "\\(\\(\\(type\\) 0.25\\) && \\(\\(type\\) 0.25 - 1\\)\\)";
might look cleaner as:
+    select    = '\(\(\(type\) 0.25\) && \(\(type\) 0.25 - 1\)\)';

Cheers - Bruce

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2008-10-24 16:56 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-10-24 17:20 [4.5] C constant expressions, VLAs etc. fixes Joseph S. Myers
2008-10-24 17:59 ` Bruce Korb

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).