Patchwork C++0x constexpr PATCHes #7-10: the rest of the compiler support

login
register
mail settings
Submitter Jason Merrill
Date Nov. 1, 2010, 2:29 a.m.
Message ID <4CCE261C.1020709@redhat.com>
Download mbox | patch
Permalink /patch/69748/
State New
Headers show

Comments

Jason Merrill - Nov. 1, 2010, 2:29 a.m.
The rest of these patches I'm not applying immediately because the last 
one depends on my fold_indirect_ref_1 patch, and it doesn't really make 
sense to apply the others without the last one; I'm just sending them to 
the list now to make the end of Stage 1.

decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P 
with the new decl_constant_var_p which also allows constexpr variables, 
adjusts when-used template instantiation to require immediate 
instantiation of constexpr functions.

constexpr-register.patch: Handles storing the definition of constexpr 
functions for later expansion.

constexpr-eval.patch: Handles the actual compile-time evaluation of 
C++0x constant expressions.

constexpr-integrate.patch: Integrates the C++0x constant expression 
semantics into the rest of the compiler.

The last patch in particular still needs some work; in particular, I 
still need to sort out the relationship between constant expression 
evaluation and value_dependent_expression_p.  I think this will just 
mean using potential_constant_expression, but it still needs to happen; 
I think this can be cleaned up in stage 3.

The other remaining cleanup is to switch the C++ front end over to a 
c_fully_fold type model of delayed folding; I had originally expected to 
do that early in development, but it turned out to be more complicated 
than I expected, so I decided to finish the functionality first.  This 
will be necessary to be fully correct in deciding what is or is not a 
constant expression.  I do not plan to do this for GCC 4.6.

Tested x86_64-pc-linux-gnu, not applied quite yet.
commit e1c3c7a78bb1d0b58389ba15b13871d2da9c05a9
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 26 19:03:56 2010 -0400

    	* decl2.c (decl_constant_var_p): New fn.
    	(decl_maybe_constant_var_p): New fn.
    	(mark_used): Rework instantiation of things needed for constant
    	expressions.
    	* cp-tree.h: Declare new fns.
    	* pt.c (instantiate_decl): Handle cp_unevaluated_operand.
    	(always_instantiate_p): Use decl_maybe_constant_var_p.
    	(instantiate_decl): Don't defer constexpr functions.
    	* repo.c (repo_emit_p): Use decl_maybe_constant_var_p.
    	* semantics.c (finish_id_expression): Use decl_constant_var_p.
    	Check for valid name in constant expr after mark_used.
commit ba4bc45580a9877d5cb04c6ef2a492c7c70c6a2e
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 27 00:22:59 2010 -0400

    	* cp-tree.h (register_constexpr_fundef): Declare.
    	* decl.c (maybe_save_function_definition): New.
    	(finish_function): Use it.
    	* semantics.c (constexpr_fundef): New datatype.
    	(constexpr_fundef_table): New global table.
    	(constexpr_fundef_equal): New.
    	(constexpr_fundef_hash): Likewise.
    	(retrieve_constexpr_fundef): Likewise.
    	(validate_constexpr_fundecl): Store in the table.
    	(build_data_member_initialization): New fn.
    	(build_constexpr_constructor_member_initializers): New.
    	(register_constexpr_fundef): Define.
    	(is_this_parameter): New.
    	(get_function_named_in_call): Likewise.
    	(get_nth_callarg): Likewise.
    	(check_automatic_or_tls): New.
    	(morally_constexpr_builtin_function_p): New.
    	(potential_constant_expression): New.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bc4eb46..4dfa8e9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5252,6 +5252,7 @@ extern void finish_handler			(tree);
 extern void finish_cleanup			(tree, tree);
 extern bool literal_type_p (tree);
 extern tree validate_constexpr_fundecl (tree);
+extern tree register_constexpr_fundef (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
 
 enum {
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b7ab080f..de6f0c4 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -12667,6 +12667,19 @@ record_key_method_defined (tree fndecl)
     }
 }
 
+/* Subroutine of finish_function.
+   Save the body of constexpr functions for possible
+   future compile time evaluation.  */
+
+static void
+maybe_save_function_definition (tree fun)
+{
+  if (!processing_template_decl
+      && DECL_DECLARED_CONSTEXPR_P (fun)
+      && !DECL_CLONED_FUNCTION_P (fun))
+    register_constexpr_fundef (fun, DECL_SAVED_TREE (fun));
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -12778,6 +12791,10 @@ finish_function (int flags)
      of curly braces for a function.  */
   gcc_assert (stmts_are_full_exprs_p ());
 
+  /* Save constexpr function body before it gets munged by
+     the NRV transformation.   */
+  maybe_save_function_definition (fndecl);
+
   /* Set up the named return value optimization, if we can.  Candidate
      variables are selected in check_return_expr.  */
   if (current_function_return_value)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ad26abb..0420d37 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5282,6 +5282,55 @@ ensure_literal_type_for_constexpr_object (tree decl)
   return decl;
 }
 
+/* Representation of entries in the constexpr function definition table.  */
+
+typedef struct GTY(()) constexpr_fundef {
+  tree decl;
+  tree body;
+} constexpr_fundef;
+
+/* This table holds all constexpr function definitions seen in
+   the current translation unit.  */
+
+static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table;
+
+static bool potential_constant_expression (tree, tsubst_flags_t);
+
+/* Utility function used for managing the constexpr function table.
+   Return true if the entries pointed to by P and Q are for the
+   same constexpr function.  */
+
+static inline int
+constexpr_fundef_equal (const void *p, const void *q)
+{
+  const constexpr_fundef *lhs = (const constexpr_fundef *) p;
+  const constexpr_fundef *rhs = (const constexpr_fundef *) q;
+  return lhs->decl == rhs->decl;
+}
+
+/* Utility function used for managing the constexpr function table.
+   Return a hash value for the entry pointed to by Q.  */
+
+static inline hashval_t
+constexpr_fundef_hash (const void *p)
+{
+  const constexpr_fundef *fundef = (const constexpr_fundef *) p;
+  return DECL_UID (fundef->decl);
+}
+
+/* Return a previously saved definition of function FUN.   */
+
+static constexpr_fundef *
+retrieve_constexpr_fundef (tree fun)
+{
+  constexpr_fundef fundef = { NULL, NULL };
+  if (constexpr_fundef_table == NULL)
+    return NULL;
+
+  fundef.decl = fun;
+  return (constexpr_fundef *) htab_find (constexpr_fundef_table, &fundef);
+}
+
 /* Return true if type expression T is a valid parameter type, or
    a valid return type, of a constexpr function.  */
 
@@ -5343,6 +5392,9 @@ is_valid_constexpr_fn (tree fun, bool complain)
 tree
 validate_constexpr_fundecl (tree fun)
 {
+  constexpr_fundef entry;
+  constexpr_fundef **slot;
+
   if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
     return NULL;
   else if (DECL_CLONED_FUNCTION_P (fun))
@@ -5355,10 +5407,684 @@ validate_constexpr_fundecl (tree fun)
       return NULL;
     }
 
+  /* Create the constexpr function table if necessary.  */
+  if (constexpr_fundef_table == NULL)
+    constexpr_fundef_table = htab_create_ggc (101,
+                                              constexpr_fundef_hash,
+                                              constexpr_fundef_equal,
+                                              ggc_free);
+  entry.decl = fun;
+  entry.body = NULL;
+  slot = (constexpr_fundef **)
+    htab_find_slot (constexpr_fundef_table, &entry, INSERT);
+  if (*slot == NULL)
+    {
+      *slot = ggc_alloc_constexpr_fundef ();
+      **slot = entry;
+    }
   return fun;
 }
 
+/* Subroutine of  build_constexpr_constructor_member_initializers.
+   The expression tree T represents a data member initialization
+   in a (constexpr) constructor definition.  Build a pairing of
+   the data member with its initializer, and prepend that pair
+   to the existing initialization pair INITS.  */
 
+static bool
+build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
+{
+  tree member, init;
+  if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == EXPR_STMT)
+    t = TREE_OPERAND (t, 0);
+  if (t == error_mark_node)
+    return false;
+  if (TREE_CODE (t) == CLEANUP_STMT)
+    /* We can't see a CLEANUP_STMT in a constructor for a literal class,
+       but we can in a constexpr constructor for a non-literal class.  Just
+       ignore it; either all the initialization will be constant, in which
+       case the cleanup can't run, or it can't be constexpr.  */
+    return true;
+  if (TREE_CODE (t) == CONVERT_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == INIT_EXPR
+      || TREE_CODE (t) == MODIFY_EXPR)
+    {
+      member = TREE_OPERAND (t, 0);
+      init = unshare_expr (TREE_OPERAND (t, 1));
+    }
+  else
+    {
+      tree memtype;
+      gcc_assert (TREE_CODE (t) == CALL_EXPR);
+      member = CALL_EXPR_ARG (t, 0);
+      memtype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (member)));
+      if (TREE_CODE (member) == NOP_EXPR)
+	{
+	  /* We don't put out anything for an empty base.  */
+	  gcc_assert (is_empty_class (memtype));
+	  /* But if the constructor used isn't constexpr, leave in the call
+	     so we complain later.  */
+	  if (potential_constant_expression (t, tf_none))
+	    return true;
+	}
+      else
+	{
+	  gcc_assert (TREE_CODE (member) == ADDR_EXPR);
+	  member = TREE_OPERAND (member, 0);
+	}
+      /* We don't use build_cplus_new here because it complains about
+	 abstract bases.  T has the wrong type, but
+	 cxx_eval_constant_expression doesn't care.  */
+      init = unshare_expr (t);
+    }
+  if (TREE_CODE (member) == COMPONENT_REF)
+    member = TREE_OPERAND (member, 1);
+  CONSTRUCTOR_APPEND_ELT (*vec, member, init);
+  return true;
+}
+
+/* Build compile-time evalable representations of member-initializer list
+   for a constexpr constructor.  */
+
+static tree
+build_constexpr_constructor_member_initializers (tree type, tree body)
+{
+  VEC(constructor_elt,gc) *vec = NULL;
+  bool ok = true;
+  if (TREE_CODE (body) == MUST_NOT_THROW_EXPR
+      || TREE_CODE (body) == EH_SPEC_BLOCK)
+    body = TREE_OPERAND (body, 0);
+  if (TREE_CODE (body) == BIND_EXPR)
+    body = BIND_EXPR_BODY (body);
+  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+    ok = build_data_member_initialization (body, &vec);
+  else
+    {
+      tree_stmt_iterator i;
+      gcc_assert (TREE_CODE (body) == STATEMENT_LIST);
+      for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+	{
+	  ok = build_data_member_initialization (tsi_stmt (i), &vec);
+	  if (!ok)
+	    break;
+	}
+    }
+  if (ok)
+    return build_constructor (type, vec);
+  else
+    return error_mark_node;
+}
+
+/* We are processing the definition of the constexpr function FUN.
+   Check that its BODY fulfills the propriate requirements and
+   enter it in the constexpr function definition table.
+   For constructor BODY is actually the TREE_LIST of the
+   member-initializer list.  */
+
+tree
+register_constexpr_fundef (tree fun, tree body)
+{
+  constexpr_fundef *fundef = retrieve_constexpr_fundef (fun);
+  gcc_assert (fundef != NULL && fundef->body == NULL);
+
+  if (DECL_CONSTRUCTOR_P (fun))
+    body = build_constexpr_constructor_member_initializers
+      (DECL_CONTEXT (fun), body);
+  else
+    {
+      if (TREE_CODE (body) == BIND_EXPR)
+	body = BIND_EXPR_BODY (body);
+      if (TREE_CODE (body) == EH_SPEC_BLOCK)
+        body = EH_SPEC_STMTS (body);
+      if (TREE_CODE (body) == MUST_NOT_THROW_EXPR)
+	body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+        body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) != RETURN_EXPR)
+        {
+          error ("body of constexpr function %qD not a return-statement", fun);
+          DECL_DECLARED_CONSTEXPR_P (fun) = false;
+          return NULL;
+        }
+      body = unshare_expr (TREE_OPERAND (body, 0));
+    }
+
+  if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun)
+					     ? tf_none : tf_error)))
+    {
+      DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      return NULL;
+    }
+  fundef->body = body;
+  return fun;
+}
+
+/* Return true if T designates the implied `this' parameter.  */
+
+static inline bool
+is_this_parameter (tree t)
+{
+  return t == current_class_ptr;
+}
+
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  If the call is lexically to a named function,
+   retrun the _DECL for that function.  */
+
+static tree
+get_function_named_in_call (tree t)
+{
+  tree fun = NULL;
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      fun = CALL_EXPR_FN (t);
+      break;
+
+    case AGGR_INIT_EXPR:
+      fun = AGGR_INIT_EXPR_FN (t);
+      break;
+
+    default:
+      gcc_unreachable();
+      break;
+    }
+  if (TREE_CODE (fun) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL)
+    fun = TREE_OPERAND (fun, 0);
+  return fun;
+}
+
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  Return the Nth argument.  */
+
+static inline tree
+get_nth_callarg (tree t, int n)
+{
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      return CALL_EXPR_ARG (t, n);
+
+    case AGGR_INIT_EXPR:
+      return AGGR_INIT_EXPR_ARG (t, n);
+
+    default:
+      gcc_unreachable ();
+      return NULL;
+    }
+}
+
+/* Return true if the object referred to by REF has automatic or thread
+   local storage.  */
+
+enum { ck_ok, ck_bad, ck_unknown };
+static int
+check_automatic_or_tls (tree ref)
+{
+  enum machine_mode mode;
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  int volatilep = 0, unsignedp = 0;
+  tree decl = get_inner_reference (ref, &bitsize, &bitpos, &offset,
+				   &mode, &unsignedp, &volatilep, false);
+  duration_kind dk;
+
+  /* If there isn't a decl in the middle, we don't know the linkage here,
+     and this isn't a constant expression anyway.  */
+  if (!DECL_P (decl))
+    return ck_unknown;
+  dk = decl_storage_duration (decl);
+  return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok;
+}
+
+/* Return true if the DECL designates a builtin function that is
+   morally constexpr, in the sense that its parameter types and
+   return type are literal types and the compiler is allowed to
+   fold its invocations.  */
+
+static bool
+morally_constexpr_builtin_function_p (tree decl)
+{
+  tree funtype = TREE_TYPE (decl);
+  tree t;
+
+  if (!is_builtin_fn (decl))
+    return false;
+  if (!literal_type_p (TREE_TYPE (funtype)))
+    return false;
+  for (t = TYPE_ARG_TYPES (funtype); t != NULL ; t = TREE_CHAIN (t))
+    {
+      if (t == void_list_node)
+        return true;
+      if (!literal_type_p (TREE_VALUE (t)))
+        return false;
+    }
+  /* We assume no varargs builtins are suitable.  */
+  return t != NULL;
+}
+
+/* Return true if T denotes a constant expression, or potential constant
+   expression if POTENTIAL is true.
+   Issue diagnostic as appropriate under control of flags.  Variables
+   with static storage duration initialized by constant expressions
+   are guaranteed to be statically initialized.
+
+   C++0x [expr.const]
+
+   6 An expression is a potential constant expression if it is
+     a constant expression where all occurences of function
+     parameters are replaced by arbitrary constant expressions
+     of the appropriate type.
+
+   2  A conditional expression is a constant expression unless it
+      involves one of the following as a potentially evaluated
+      subexpression (3.2), but subexpressions of logical AND (5.14),
+      logical OR (5.15), and conditional (5.16) operations that are
+      not evaluated are not considered.   */
+
+static bool
+potential_constant_expression (tree t, tsubst_flags_t flags)
+{
+  int i;
+  tree tmp;
+  if (t == error_mark_node)
+    return false;
+  if (TREE_THIS_VOLATILE (t))
+    {
+      if (flags & tf_error)
+        error ("expression %qE has side-effects", t);
+      return false;
+    }
+  if (CONSTANT_CLASS_P (t))
+    return true;
+
+  switch (TREE_CODE (t))
+    {
+    case FUNCTION_DECL:
+    case LABEL_DECL:
+    case CONST_DECL:
+      return true;
+
+    case PARM_DECL:
+      /* -- this (5.1) unless it appears as the postfix-expression in a
+            class member access expression, including the result of the
+            implicit transformation in the body of the non-static
+            member function (9.3.1);  */
+      if (is_this_parameter (t))
+        {
+          if (flags & tf_error)
+            error ("%qE is not a potential constant expression", t);
+          return false;
+        }
+      return true;
+
+    case AGGR_INIT_EXPR:
+    case CALL_EXPR:
+      /* -- an invocation of a function other than a constexpr function
+            or a constexpr constructor.  */
+      {
+        tree fun = get_function_named_in_call (t);
+        const int nargs = call_expr_nargs (t);
+        if (TREE_CODE (fun) != FUNCTION_DECL)
+          {
+	    if (potential_constant_expression (fun, flags))
+	      /* Might end up being a constant function pointer.  */
+	      return true;
+            if (flags & tf_error)
+              error ("%qE is not a function name", fun);
+            return false;
+          }
+	/* Skip initial arguments to base constructors.  */
+	if (DECL_BASE_CONSTRUCTOR_P (fun))
+	  i = num_artificial_parms_for (fun);
+	else
+	  i = 0;
+	fun = DECL_ORIGIN (fun);
+        if (builtin_valid_in_constant_expr_p (fun))
+          return true;
+        if (!DECL_DECLARED_CONSTEXPR_P (fun)
+            && !morally_constexpr_builtin_function_p (fun))
+          {
+            if (flags & tf_error)
+              error ("%qD is not %<constexpr%>", fun);
+            return false;
+          }
+        for (; i < nargs; ++i)
+          {
+            tree x = get_nth_callarg (t, i);
+            /* A call to a non-static member function takes the
+               address of the object as the first argument.
+               But in a constant expression the address will be folded
+	       away, so look through it now.  */
+            if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
+                && !DECL_CONSTRUCTOR_P (fun))
+	      {
+		if (TREE_CODE (x) == ADDR_EXPR)
+		  x = TREE_OPERAND (x, 0);
+		if (is_this_parameter (x))
+		  /* OK.  */;
+                else if (!potential_constant_expression (x, flags))
+		  {
+		    if (flags & tf_error)
+		      error ("object argument is not a potential constant "
+			     "expression");
+		    return false;
+		  }
+              }
+	    else if (!potential_constant_expression (x, flags))
+	      {
+		if (flags & tf_error)
+		  error ("argument in position %qP is not a "
+			 "potential constant expression", i);
+		return false;
+              }
+          }
+        return true;
+      }
+
+    case NON_LVALUE_EXPR:
+      /* -- an lvalue-to-rvalue conversion (4.1) unless it is applied to
+            -- an lvalue of integral type that refers to a non-volatile
+               const variable or static data member initialized with
+               constant expressions, or
+
+            -- an lvalue of literal type that refers to non-volatile
+               object defined with constexpr, or that refers to a
+               sub-object of such an object;  */
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case VAR_DECL:
+      if (!decl_constant_var_p (t))
+        {
+          if (flags & tf_error)
+            error ("variable %qD is not declared constexpr", t);
+          return false;
+        }
+      return true;
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+      /* -- an array-to-pointer conversion that is applied to an lvalue
+            that designates an object with thread or automatic storage
+            duration;  FIXME not implemented as it breaks constexpr arrays;
+	    need to fix the standard
+         -- a type conversion from a pointer or pointer-to-member type
+            to a literal type.  */
+      {
+        tree from = TREE_OPERAND (t, 0);
+        tree source = TREE_TYPE (from);
+        tree target = TREE_TYPE (t);
+        if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (target)
+	    && !(TREE_CODE (from) == COMPONENT_REF
+		 && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (from, 0)))))
+          {
+            if (flags & tf_error)
+              error ("conversion of expression %qE of pointer type "
+                     "cannot yield a constant expression", from);
+            return false;
+          }
+        return potential_constant_expression (from, flags);
+      }
+
+    case ADDR_EXPR:
+      /* -- a unary operator & that is applied to an lvalue that
+            designates an object with thread or automatic storage
+            duration;  */
+      t = TREE_OPERAND (t, 0);
+      i = check_automatic_or_tls (t);
+      if (i == ck_ok)
+	return true;
+      if (i == ck_bad)
+        {
+          if (flags & tf_error)
+            error ("address-of an object %qE with thread local or "
+                   "automatic storage is not a constant expression", t);
+          return false;
+        }
+      return potential_constant_expression (t, flags);
+
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+      /* -- a class member access unless its postfix-expression is
+            of literal type or of pointer to literal type.  */
+      /* This test would be redundant, as it follows from the
+	 postfix-expression being a potential constant expression.  */
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case INDIRECT_REF:
+      {
+        tree x = TREE_OPERAND (t, 0);
+        STRIP_NOPS (x);
+        if (is_this_parameter (x))
+	  return true;
+	return potential_constant_expression (x, flags);
+      }
+
+    case LAMBDA_EXPR:
+    case DYNAMIC_CAST_EXPR:
+    case PSEUDO_DTOR_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+    case DELETE_EXPR:
+    case VEC_DELETE_EXPR:
+    case THROW_EXPR:
+    case MODIFY_EXPR:
+    case MODOP_EXPR:
+      /* GCC internal stuff.  */
+    case VA_ARG_EXPR:
+    case OBJ_TYPE_REF:
+    case WITH_CLEANUP_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case MUST_NOT_THROW_EXPR:
+    case TRY_CATCH_EXPR:
+    case STATEMENT_LIST:
+    case BIND_EXPR:
+      if (flags & tf_error)
+        error ("expression %qE is not a constant-expression", t);
+      return false;
+
+    case TYPEID_EXPR:
+      /* -- a typeid expression whose operand is of polymorphic
+            class type;  */
+      {
+        tree e = TREE_OPERAND (t, 0);
+        if (!TYPE_P (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+          {
+            if (flags & tf_error)
+              error ("typeid-expression is not a constant expression "
+                     "because %qE is of polymorphic type", e);
+            return false;
+          }
+        return true;
+      }
+
+    case MINUS_EXPR:
+      /* -- a subtraction where both operands are pointers.   */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          && TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("difference of two pointer expressions is not "
+                   "a constant expression");
+          return false;
+        }
+      goto binary;
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* -- a relational or equality operator where at least
+            one of the operands is a pointer.  */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          || TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("pointer comparison expression is not a "
+                   "constant expression");
+          return false;
+        }
+      goto binary;
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case SAVE_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PAREN_EXPR:
+    case FIXED_CONVERT_EXPR:
+      /* For convenience.  */
+    case RETURN_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case INIT_EXPR:
+    case TARGET_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+
+    case CONSTRUCTOR:
+      {
+        VEC(constructor_elt, gc) *v = CONSTRUCTOR_ELTS (t);
+        constructor_elt *ce;
+        for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
+	  if (!potential_constant_expression (ce->value, flags))
+	    return false;
+	return true;
+      }
+
+    case TREE_LIST:
+      {
+	gcc_assert (TREE_PURPOSE (t) == NULL_TREE
+		    || DECL_P (TREE_PURPOSE (t)));
+	if (!potential_constant_expression (TREE_VALUE (t), flags))
+	  return false;
+	if (TREE_CHAIN (t) == NULL_TREE)
+	  return true;
+	return potential_constant_expression (TREE_CHAIN (t), flags);
+      }
+
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      if (integer_zerop (decl_constant_value (TREE_OPERAND (t, 1))))
+	return false;
+      else
+	goto binary;
+
+    case COMPOUND_EXPR:
+      {
+	/* check_return_expr sometimes wraps a TARGET_EXPR in a
+	   COMPOUND_EXPR; don't get confused.  Also handle EMPTY_CLASS_EXPR
+	   introduced by build_call_a.  */
+	tree op0 = TREE_OPERAND (t, 0);
+	tree op1 = TREE_OPERAND (t, 1);
+	STRIP_NOPS (op1);
+	if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
+	    || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
+	  return potential_constant_expression (op0, flags);
+	else
+	  goto binary;
+      }
+
+      /* If the first operand is the non-short-circuit constant, look at
+	 the second operand; otherwise we only care about the first one for
+	 potentiality.  */
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+      tmp = boolean_true_node;
+      goto truth;
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+      tmp = boolean_false_node;
+    truth:
+      if (TREE_OPERAND (t, 0) == tmp)
+	return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      else
+	return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case PLUS_EXPR:
+    case MULT_EXPR:
+    case POINTER_PLUS_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case RANGE_EXPR:
+    case COMPLEX_EXPR:
+    binary:
+      for (i = 0; i < 2; ++i)
+	if (!potential_constant_expression (TREE_OPERAND (t, i),
+				      flags))
+	  return false;
+      return true;
+
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      /* If the condition is a known constant, we know which of the legs we
+	 care about; otherwise we only require that the condition and
+	 either of the legs be potentially constant.  */
+      tmp = TREE_OPERAND (t, 0);
+      if (!potential_constant_expression (tmp, flags))
+	return false;
+      else if (tmp == boolean_true_node)
+	return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      else if (tmp == boolean_false_node)
+	return potential_constant_expression (TREE_OPERAND (t, 2), flags);
+      for (i = 1; i < 3; ++i)
+	if (potential_constant_expression (TREE_OPERAND (t, i), tf_none))
+	  return true;
+      if (flags & tf_error)
+        error ("expression %qE is not a constant-expression", t);
+      return false;
+
+    case VEC_INIT_EXPR:
+      /* We should only see this in a defaulted constructor for a class
+	 with a non-static data member of array type; if we get here we
+	 know this is a potential constant expression.  */
+      gcc_assert (DECL_DEFAULTED_FN (current_function_decl));
+      return true;
+
+    default:
+      sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
+      gcc_unreachable();
+      return false;
+    }
+}
+
+
 /* Constructor for a lambda expression.  */
 
 tree
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor2.C
new file mode 100644
index 0000000..5280b13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor2.C
@@ -0,0 +1,11 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  A();
+};
+
+struct B : A
+{
+  constexpr B(): A() { }	// { dg-error "A::A" }
+};
commit 18599f6788f8dca4f11717e81bd3ea5cf152c0d0
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 26 21:37:55 2010 -0400

    	* semantics.c (constexpr_call): New datatype.
    	(constexpr_call_table): New global table.
    	(constexpr_call_hash): New.
    	(constexpr_call_equal): Likewise.
    	(maybe_initialize_constexpr_call_table): Likewise.
    	(lookup_parameter_binding): Likewise.
    	(cxx_eval_builtin_function_call): Likewise.
    	(cxx_bind_parameters_in_call): Likewise.
    	(cxx_eval_call_expression): Likewise.
    	(cxx_eval_unary_expression): Likewise.
    	(cxx_eval_binary_expression): Likewise.
    	(cxx_eval_conditional_expression): Likewise.
    	(cxx_eval_array_reference): Likewise.
    	(cxx_eval_component_reference): Likewise.
    	(cxx_eval_logical_expression): Likewise.
    	(cxx_eval_object_construction): Likewise.
    	(cxx_eval_constant_expression): Likewise.
    	(cxx_eval_indirect_ref): Likewise.
    	(cxx_constant_value): Likewise.
    	(cxx_eval_bare_aggregate): Likewise.
    	(adjust_temp_type): New.
    	(reduced_constant_expression_p): New.
    	(verify_constant): New.
    	(cxx_eval_vec_init, cxx_eval_vec_init_1): New.
    	(cxx_eval_outermost_constant_expr): New.
    	(maybe_constant_value, maybe_constant_init): New.
    	(cxx_eval_constant_expression): Use them.
    	* cp-tree.h: Declare fns.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4dfa8e9..96fefae 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5122,6 +5122,7 @@ extern tree get_template_innermost_arguments	(const_tree);
 extern tree get_template_argument_pack_elems	(const_tree);
 extern tree get_function_template_decl		(const_tree);
 extern tree resolve_nondeduced_context		(tree);
+extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
 
 /* in repo.c */
 extern void init_repo				(void);
@@ -5254,6 +5255,10 @@ extern bool literal_type_p (tree);
 extern tree validate_constexpr_fundecl (tree);
 extern tree register_constexpr_fundef (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
+extern tree cxx_constant_value (tree);
+extern tree maybe_constant_value (tree);
+extern tree maybe_constant_init (tree);
+extern bool reduced_constant_expression_p (tree);
 
 enum {
   BCS_NO_SCOPE = 1,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0047aae..9a72ea8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -187,7 +187,6 @@ static tree tsubst_decl (tree, tree, tsubst_flags_t);
 static void perform_typedefs_access_check (tree tmpl, tree targs);
 static void append_type_to_template_for_access_check_1 (tree, tree, tree,
 							location_t);
-static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 
@@ -1458,7 +1457,7 @@ hash_specialization (const void *p)
 /* Recursively calculate a hash value for a template argument ARG, for use
    in the hash tables of template specializations.  */
 
-static hashval_t
+hashval_t
 iterative_hash_template_arg (tree arg, hashval_t val)
 {
   unsigned HOST_WIDE_INT i;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0420d37..039f0a5 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5562,6 +5562,89 @@ register_constexpr_fundef (tree fun, tree body)
   return fun;
 }
 
+/* Objects of this type represent calls to constexpr functions
+   along with the bindings of parameters to their arguments, for
+   the purpose of compile time evaluation.  */
+
+typedef struct GTY(()) constexpr_call {
+  /* Description of the constexpr function definition.  */
+  constexpr_fundef *fundef;
+  /* Parameter bindings enironment.  A TREE_LIST where each TREE_PURPOSE
+     is a parameter _DECL and the TREE_VALUE is the value of the parameter.
+     Note: This arrangement is made to accomodate the use of
+     iterative_hash_template_arg (see pt.c).  If you change this
+     representation, also change the hash calculation in
+     cxx_eval_call_expression.  */
+  tree bindings;
+  /* Result of the call.
+       NULL means the call is being evaluated.
+       error_mark_node means that the evaluation was erroneous;
+       otherwise, the actuall value of the call.  */
+  tree result;
+  /* The hash of this call; we remember it here to avoid having to
+     recalculate it when expanding the hash table.  */
+  hashval_t hash;
+} constexpr_call;
+
+/* A table of all constexpr calls that have been evaluated by the
+   compiler in this translation unit.  */
+
+static GTY ((param_is (constexpr_call))) htab_t constexpr_call_table;
+
+static tree cxx_eval_constant_expression (const constexpr_call *, tree,
+					  bool, bool, bool *);
+
+/* Compute a hash value for a constexpr call representation.  */
+
+static hashval_t
+constexpr_call_hash (const void *p)
+{
+  const constexpr_call *info = (const constexpr_call *) p;
+  return info->hash;
+}
+
+/* Return 1 if the objects pointed to by P and Q represent calls
+   to the same constexpr function with the same arguments.
+   Otherwise, return 0.  */
+
+static int
+constexpr_call_equal (const void *p, const void *q)
+{
+  const constexpr_call *lhs = (const constexpr_call *) p;
+  const constexpr_call *rhs = (const constexpr_call *) q;
+  tree lhs_bindings;
+  tree rhs_bindings;
+  if (lhs == rhs)
+    return 1;
+  if (!constexpr_fundef_equal (lhs->fundef, rhs->fundef))
+    return 0;
+  lhs_bindings = lhs->bindings;
+  rhs_bindings = rhs->bindings;
+  while (lhs_bindings != NULL && rhs_bindings != NULL)
+    {
+      tree lhs_arg = TREE_VALUE (lhs_bindings);
+      tree rhs_arg = TREE_VALUE (rhs_bindings);
+      gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg));
+      if (!cp_tree_equal (lhs_arg, rhs_arg))
+        return 0;
+      lhs_bindings = TREE_CHAIN (lhs_bindings);
+      rhs_bindings = TREE_CHAIN (rhs_bindings);
+    }
+  return lhs_bindings == rhs_bindings;
+}
+
+/* Initialize the constexpr call table, if needed.  */
+
+static void
+maybe_initialize_constexpr_call_table (void)
+{
+  if (constexpr_call_table == NULL)
+    constexpr_call_table = htab_create_ggc (101,
+                                            constexpr_call_hash,
+                                            constexpr_call_equal,
+                                            ggc_free);
+}
+
 /* Return true if T designates the implied `this' parameter.  */
 
 static inline bool
@@ -5618,6 +5701,1195 @@ get_nth_callarg (tree t, int n)
     }
 }
 
+/* Look up the binding of the function parameter T in a constexpr
+   function call context CALL.  */
+
+static tree
+lookup_parameter_binding (const constexpr_call *call, tree t)
+{
+  tree b = purpose_member (t, call->bindings);
+  return TREE_VALUE (b);
+}
+
+/* Attempt to evaluate T which represents a call to a builtin function.
+   We assume here that all builtin functions evaluate to scalar types
+   represented by _CST nodes.  */
+
+static tree
+cxx_eval_builtin_function_call (const constexpr_call *call, tree t,
+				bool allow_non_constant, bool addr,
+				bool *non_constant_p)
+{
+  const int nargs = call_expr_nargs (t);
+  tree *args = (tree *) alloca (nargs * sizeof (tree));
+  tree new_call;
+  int i;
+  for (i = 0; i < nargs; ++i)
+    {
+      args[i] = cxx_eval_constant_expression (call, CALL_EXPR_ARG (t, i),
+					      allow_non_constant, addr,
+					      non_constant_p);
+      if (allow_non_constant && *non_constant_p)
+	return t;
+    }
+  if (*non_constant_p)
+    return t;
+  new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+                                   CALL_EXPR_FN (t), nargs, args);
+  return fold (new_call);
+}
+
+/* TEMP is the constant value of a temporary object of type TYPE.  Adjust
+   the type of the value to match.  */
+
+static tree
+adjust_temp_type (tree type, tree temp)
+{
+  if (TREE_TYPE (temp) == type)
+    return temp;
+  /* Avoid wrapping an aggregate value in a NOP_EXPR.  */
+  if (TREE_CODE (temp) == CONSTRUCTOR)
+    return build_constructor (type, CONSTRUCTOR_ELTS (temp));
+  gcc_assert (SCALAR_TYPE_P (type));
+  return fold_convert (type, temp);
+}
+
+/* Subroutine of cxx_eval_call_expression.
+   We are processing a call expression (either CALL_EXPR or
+   AGGR_INIT_EXPR) in the call context of OLD_CALL.  Evaluate
+   all arguments and bind their values to correspondings
+   parameters, making up the NEW_CALL context.  */
+
+static void
+cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
+                             constexpr_call *new_call,
+			     bool allow_non_constant,
+			     bool *non_constant_p)
+{
+  const int nargs = call_expr_nargs (t);
+  tree fun = new_call->fundef->decl;
+  tree parms = DECL_ARGUMENTS (fun);
+  int i;
+  for (i = 0; i < nargs; ++i)
+    {
+      tree x, arg;
+      tree type = parms ? TREE_TYPE (parms) : void_type_node;
+      /* For member function, the first argument is a pointer to the implied
+         object.  And for an object contruction, don't bind `this' before
+         it is fully constructed.  */
+      if (i == 0 && DECL_CONSTRUCTOR_P (fun))
+        goto next;
+      x = get_nth_callarg (t, i);
+      arg = cxx_eval_constant_expression (old_call, x, allow_non_constant,
+					  TREE_CODE (type) == REFERENCE_TYPE,
+					  non_constant_p);
+      /* Don't VERIFY_CONSTANT here.  */
+      if (*non_constant_p && allow_non_constant)
+	return;
+      /* Just discard ellipsis args after checking their constantitude.  */
+      if (!parms)
+	continue;
+
+      /* Make sure the binding has the same type as the parm.  */
+      if (TREE_CODE (type) != REFERENCE_TYPE)
+	arg = adjust_temp_type (type, arg);
+      new_call->bindings = tree_cons (parms, arg, new_call->bindings);
+    next:
+      parms = TREE_CHAIN (parms);
+    }
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Evaluate the call expression tree T in the context of OLD_CALL expression
+   evaluation.  */
+
+static tree
+cxx_eval_call_expression (const constexpr_call *old_call, tree t,
+			  bool allow_non_constant, bool addr,
+			  bool *non_constant_p)
+{
+  location_t loc = EXPR_LOCATION (t);
+  tree fun = get_function_named_in_call (t);
+  tree result;
+  constexpr_call new_call = { NULL, NULL, NULL, 0 };
+  constexpr_call **slot;
+  if (loc == UNKNOWN_LOCATION)
+    loc = input_location;
+  if (TREE_CODE (fun) != FUNCTION_DECL)
+    {
+      /* Might be a constexpr function pointer.  */
+      fun = cxx_eval_constant_expression (old_call, fun, allow_non_constant,
+					  /*addr*/false, non_constant_p);
+      if (TREE_CODE (fun) == ADDR_EXPR)
+	fun = TREE_OPERAND (fun, 0);
+    }
+  if (TREE_CODE (fun) != FUNCTION_DECL)
+    {
+      if (!allow_non_constant)
+	error_at (loc, "expression %qE does not designate a constexpr "
+		  "function", fun);
+      *non_constant_p = true;
+      return t;
+    }
+  if (DECL_CLONED_FUNCTION_P (fun))
+    fun = DECL_CLONED_FUNCTION (fun);
+  if (is_builtin_fn (fun))
+    return cxx_eval_builtin_function_call (old_call, t, allow_non_constant,
+					   addr, non_constant_p);
+  if (!DECL_DECLARED_CONSTEXPR_P (fun))
+    {
+      if (!allow_non_constant)
+	{
+	  error_at (loc, "%qD is not a constexpr function", fun);
+	  if (DECL_TEMPLATE_INSTANTIATION (fun)
+	      && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
+					    (DECL_TI_TEMPLATE (fun))))
+	    is_valid_constexpr_fn (fun, true);
+	}
+      *non_constant_p = true;
+      return t;
+    }
+
+  /* If in direct recursive call, optimize definition search.  */
+  if (old_call != NULL && old_call->fundef->decl == fun)
+    new_call.fundef = old_call->fundef;
+  else
+    {
+      new_call.fundef = retrieve_constexpr_fundef (fun);
+      if (new_call.fundef == NULL || new_call.fundef->body == NULL)
+        {
+	  if (!allow_non_constant)
+	    error_at (loc, "%qD used before its definition", fun);
+	  *non_constant_p = true;
+          return t;
+        }
+    }
+  cxx_bind_parameters_in_call (old_call, t, &new_call,
+			       allow_non_constant, non_constant_p);
+  if (*non_constant_p)
+    return t;
+
+  new_call.hash
+    = iterative_hash_template_arg (new_call.bindings,
+				   constexpr_fundef_hash (new_call.fundef));
+
+  /* If we have seen this call before, we are done.  */
+  maybe_initialize_constexpr_call_table ();
+  slot = (constexpr_call **)
+    htab_find_slot (constexpr_call_table, &new_call, INSERT);
+  if (*slot != NULL)
+    {
+      /* Calls which are in progress have their result set to NULL
+         so that we can detect circular dependencies.  */
+      if ((*slot)->result == NULL)
+        {
+	  if (!allow_non_constant)
+	    error ("call has circular dependency");
+	  (*slot)->result = result = error_mark_node;
+        }
+      else
+	{
+	  result = (*slot)->result;
+	  if (result == error_mark_node && !allow_non_constant)
+	    /* Re-evaluate to get the error.  */
+	    cxx_eval_constant_expression (&new_call, new_call.fundef->body,
+					  allow_non_constant, addr,
+					  non_constant_p);
+	}
+    }
+  else
+    {
+      /* We need to keep a pointer to the entry, not just the slot, as the
+	 slot can move in the call to cxx_eval_builtin_function_call.  */
+      constexpr_call *entry = ggc_alloc_constexpr_call ();
+      *entry = new_call;
+      *slot = entry;
+      result
+	= cxx_eval_constant_expression (&new_call, new_call.fundef->body,
+					allow_non_constant, addr,
+					non_constant_p);
+      if (*non_constant_p)
+	entry->result = result = error_mark_node;
+      else
+	{
+	  /* If this was a call to initialize an object, set the type of
+	     the CONSTRUCTOR to the type of that object.  */
+	  if (DECL_CONSTRUCTOR_P (fun))
+	    {
+	      tree ob_arg = get_nth_callarg (t, 0);
+	      STRIP_NOPS (ob_arg);
+	      gcc_assert (TREE_CODE (TREE_TYPE (ob_arg)) == POINTER_TYPE
+			  && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (ob_arg))));
+	      result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)),
+					 result);
+	    }
+	  entry->result = result;
+	}
+    }
+
+  if (result == error_mark_node)
+    {
+      if (!allow_non_constant)
+	error_at (loc, "in expansion of %qE", t);
+      *non_constant_p = true;
+      result = t;
+    }
+  return result;
+}
+
+bool
+reduced_constant_expression_p (tree t)
+{
+  /* FIXME speed this up, it's taking 16% of compile time on sieve testcase.  */
+  if (cxx_dialect >= cxx0x && TREE_OVERFLOW_P (t))
+    /* In C++0x, integer overflow makes this not a constant expression.
+       FIXME arithmetic overflow is different from conversion truncation */
+    return false;
+  /* FIXME are we calling this too much?  */
+  return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
+}
+
+/* Some expressions may have constant operands but are not constant
+   themselves, such as 1/0.  Call this function (or rather, the macro
+   following it) to check for that condition.
+
+   We only call this in places that require an arithmetic constant, not in
+   places where we might have a non-constant expression that can be a
+   component of a constant expression, such as the address of a constexpr
+   variable that might be dereferenced later.  */
+
+static bool
+verify_constant (tree t, bool allow_non_constant, bool *non_constant_p)
+{
+  if (!*non_constant_p && !reduced_constant_expression_p (t))
+    {
+      if (!allow_non_constant)
+	error ("%qE is not a constant expression", t);
+      *non_constant_p = true;
+    }
+  return *non_constant_p;
+}
+#define VERIFY_CONSTANT(X)						\
+do {									\
+  if (verify_constant ((X), allow_non_constant, non_constant_p))	\
+    return t;								\
+ } while (0)
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce the unary expression tree T to a compile time value.
+   If successful, return the value.  Otherwise issue a diagnostic
+   and return error_mark_node.  */
+
+static tree
+cxx_eval_unary_expression (const constexpr_call *call, tree t,
+			   bool allow_non_constant, bool addr,
+			   bool *non_constant_p)
+{
+  tree r;
+  tree orig_arg = TREE_OPERAND (t, 0);
+  tree arg = cxx_eval_constant_expression (call, orig_arg, allow_non_constant,
+					   addr, non_constant_p);
+  VERIFY_CONSTANT (arg);
+  if (arg == orig_arg)
+    return t;
+  r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), arg);
+  VERIFY_CONSTANT (r);
+  return r;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Like cxx_eval_unary_expression, except for binary expressions.  */
+
+static tree
+cxx_eval_binary_expression (const constexpr_call *call, tree t,
+			    bool allow_non_constant, bool addr,
+			    bool *non_constant_p)
+{
+  tree r;
+  tree orig_lhs = TREE_OPERAND (t, 0);
+  tree orig_rhs = TREE_OPERAND (t, 1);
+  tree lhs, rhs;
+  lhs = cxx_eval_constant_expression (call, orig_lhs,
+				      allow_non_constant, addr,
+				      non_constant_p);
+  VERIFY_CONSTANT (lhs);
+  rhs = cxx_eval_constant_expression (call, orig_rhs,
+				      allow_non_constant, addr,
+				      non_constant_p);
+  VERIFY_CONSTANT (rhs);
+  if (lhs == orig_lhs && rhs == orig_rhs)
+    return t;
+  r = fold_build2 (TREE_CODE (t), TREE_TYPE (t), lhs, rhs);
+  VERIFY_CONSTANT (r);
+  return r;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to evaluate condition expressions.  Dead branches are not
+   looked into.  */
+
+static tree
+cxx_eval_conditional_expression (const constexpr_call *call, tree t,
+				 bool allow_non_constant, bool addr,
+				 bool *non_constant_p)
+{
+  tree val = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+					   allow_non_constant, addr,
+					   non_constant_p);
+  VERIFY_CONSTANT (val);
+  if (val == boolean_true_node)
+    return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+					 allow_non_constant, addr,
+					 non_constant_p);
+  gcc_assert (val == boolean_false_node);
+  /* Don't VERIFY_CONSTANT here.  */
+  return cxx_eval_constant_expression (call, TREE_OPERAND (t, 2),
+				       allow_non_constant, addr,
+				       non_constant_p);
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce a reference to an array slot.  */
+
+static tree
+cxx_eval_array_reference (const constexpr_call *call, tree t,
+			  bool allow_non_constant, bool addr,
+			  bool *non_constant_p)
+{
+  tree oldary = TREE_OPERAND (t, 0);
+  tree ary = cxx_eval_constant_expression (call, oldary,
+					   allow_non_constant, addr,
+					   non_constant_p);
+  tree index, oldidx;
+  HOST_WIDE_INT i;
+  unsigned len;
+  if (*non_constant_p)
+    return t;
+  oldidx = TREE_OPERAND (t, 1);
+  index = cxx_eval_constant_expression (call, oldidx,
+					allow_non_constant, false,
+					non_constant_p);
+  VERIFY_CONSTANT (index);
+  if (addr && ary == oldary && index == oldidx)
+    return t;
+  else if (addr)
+    return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
+  len = (TREE_CODE (ary) == CONSTRUCTOR
+	 ? CONSTRUCTOR_NELTS (ary)
+	 : (unsigned)TREE_STRING_LENGTH (ary));
+  if (compare_tree_int (index, len) >= 0)
+    {
+      if (!allow_non_constant)
+	error ("array subscript out of bound");
+      *non_constant_p = true;
+      return t;
+    }
+  i = tree_low_cst (index, 0);
+  if (TREE_CODE (ary) == CONSTRUCTOR)
+    return VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ary), i)->value;
+  else
+    return build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))),
+			  TREE_STRING_POINTER (ary)[i]);
+  /* Don't VERIFY_CONSTANT here.  */
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce a field access of a value of class type.  */
+
+static tree
+cxx_eval_component_reference (const constexpr_call *call, tree t,
+			      bool allow_non_constant, bool addr,
+			      bool *non_constant_p)
+{
+  unsigned HOST_WIDE_INT i;
+  tree field;
+  tree value;
+  tree part = TREE_OPERAND (t, 1);
+  tree orig_whole = TREE_OPERAND (t, 0);
+  tree whole = cxx_eval_constant_expression (call, orig_whole,
+					     allow_non_constant, addr,
+					     non_constant_p);
+  if (whole == orig_whole)
+    return t;
+  if (addr)
+    return fold_build3 (COMPONENT_REF, TREE_TYPE (t),
+			whole, part, NULL_TREE);
+  /* Don't VERIFY_CONSTANT here; we only want to check that we got a
+     CONSTRUCTOR.  */
+  if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR)
+    {
+      if (!allow_non_constant)
+	error ("%qE is not a constant expression", orig_whole);
+      *non_constant_p = true;
+    }
+  if (*non_constant_p)
+    return t;
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
+    {
+      if (field == part)
+        return value;
+    }
+  if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE)
+    {
+      /* FIXME Mike Miller wants this to be OK.  */
+      if (!allow_non_constant)
+	error ("accessing %qD member instead of initialized %qD member in "
+	       "constant expression", part, CONSTRUCTOR_ELT (whole, 0)->index);
+      *non_constant_p = true;
+      return t;
+    }
+  gcc_unreachable();
+  return error_mark_node;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Evaluate a short-circuited logical expression T in the context
+   of a given constexpr CALL.  BAILOUT_VALUE is the value for
+   early return.  CONTINUE_VALUE is used here purely for
+   sanity check purposes.  */
+
+static tree
+cxx_eval_logical_expression (const constexpr_call *call, tree t,
+                             tree bailout_value, tree continue_value,
+			     bool allow_non_constant, bool addr,
+			     bool *non_constant_p)
+{
+  tree r;
+  tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+					   allow_non_constant, addr,
+					   non_constant_p);
+  VERIFY_CONSTANT (lhs);
+  if (lhs == bailout_value)
+    return lhs;
+  gcc_assert (lhs == continue_value);
+  r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+				    allow_non_constant, addr, non_constant_p);
+  VERIFY_CONSTANT (r);
+  return r;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   The expression tree T denotes a C-style array or a C-style
+   aggregate.  Reduce it to a constant expression.  */
+
+static tree
+cxx_eval_bare_aggregate (const constexpr_call *call, tree t,
+			 bool allow_non_constant, bool addr,
+			 bool *non_constant_p)
+{
+  VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (t);
+  VEC(constructor_elt,gc) *n = VEC_alloc (constructor_elt, gc,
+					  VEC_length (constructor_elt, v));
+  constructor_elt *ce;
+  HOST_WIDE_INT i;
+  bool changed = false;
+  tree type = TREE_TYPE (t);
+  gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t));
+  for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
+    {
+      tree elt = cxx_eval_constant_expression (call, ce->value,
+					       allow_non_constant, addr,
+					       non_constant_p);
+      /* Don't VERIFY_CONSTANT here.  */
+      if (allow_non_constant && *non_constant_p)
+	goto fail;
+      if (elt != ce->value)
+	changed = true;
+      if (TREE_CODE (type) != ARRAY_TYPE
+	  && !(same_type_ignoring_top_level_qualifiers_p
+	       (DECL_CONTEXT (ce->index), type)))
+	{
+	  /* Push our vtable pointer down into the base where it belongs.  */
+	  tree vptr_base = DECL_CONTEXT (ce->index);
+	  tree base_ctor;
+	  gcc_assert (ce->index == TYPE_VFIELD (type));
+	  for (base_ctor = VEC_index (constructor_elt, n, 0)->value; ;
+	       base_ctor = CONSTRUCTOR_ELT (base_ctor, 0)->value)
+	    if (TREE_TYPE (base_ctor) == vptr_base)
+	      {
+		constructor_elt *p = CONSTRUCTOR_ELT (base_ctor, 0);
+		gcc_assert (p->index == ce->index);
+		p->value = elt;
+		break;
+	      }
+	}
+      else
+	CONSTRUCTOR_APPEND_ELT (n, ce->index, elt);
+    }
+  if (*non_constant_p || !changed)
+    {
+    fail:
+      VEC_free (constructor_elt, gc, n);
+      return t;
+    }
+  t = build_constructor (TREE_TYPE (t), n);
+  TREE_CONSTANT (t) = true;
+  return t;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   The expression tree T is a VEC_INIT_EXPR which denotes the desired
+   initialization of a non-static data member of array type.  Reduce it to a
+   CONSTRUCTOR.
+
+   Note that this is only intended to support the initializations done by
+   defaulted constructors for classes with non-static data members of array
+   type.  In this case, VEC_INIT_EXPR_INIT will either be NULL_TREE for the
+   default constructor, or a COMPONENT_REF for the copy/move
+   constructor.  */
+
+static tree
+cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
+		     bool allow_non_constant, bool addr,
+		     bool *non_constant_p)
+{
+  tree elttype = TREE_TYPE (atype);
+  int max = tree_low_cst (array_type_nelts (atype), 0);
+  VEC(constructor_elt,gc) *n = VEC_alloc (constructor_elt, gc, max + 1);
+  int i;
+
+  /* For the default constructor, build up a call to the default
+     constructor of the element type.  We only need to handle class types
+     here, as for a constructor to be constexpr, all members must be
+     initialized, which for a defaulted default constructor means they must
+     be of a class type with a constexpr default constructor.  */
+  if (!init)
+    {
+      VEC(tree,gc) *argvec = make_tree_vector ();
+      init = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+					&argvec, elttype, LOOKUP_NORMAL,
+					tf_warning_or_error);
+      release_tree_vector (argvec);
+      init = cxx_eval_constant_expression (call, init, allow_non_constant,
+					   addr, non_constant_p);
+    }
+
+  if (*non_constant_p && !allow_non_constant)
+    goto fail;
+
+  for (i = 0; i <= max; ++i)
+    {
+      tree idx = build_int_cst (size_type_node, i);
+      tree eltinit;
+      if (TREE_CODE (elttype) == ARRAY_TYPE)
+	{
+	  /* A multidimensional array; recurse.  */
+	  eltinit = cp_build_array_ref (input_location, init, idx,
+					tf_warning_or_error);
+	  eltinit = cxx_eval_vec_init_1 (call, elttype, eltinit,
+					 allow_non_constant, addr,
+					 non_constant_p);
+	}
+      else if (TREE_CODE (init) == CONSTRUCTOR)
+	{
+	  /* Initializing an element using the call to the default
+	     constructor we just built above.  */
+	  eltinit = unshare_expr (init);
+	}
+      else
+	{
+	  /* Copying an element.  */
+	  VEC(tree,gc) *argvec;
+	  gcc_assert (same_type_ignoring_top_level_qualifiers_p
+		      (atype, TREE_TYPE (init)));
+	  eltinit = cp_build_array_ref (input_location, init, idx,
+					tf_warning_or_error);
+	  if (!real_lvalue_p (init))
+	    eltinit = move (eltinit);
+	  argvec = make_tree_vector ();
+	  VEC_quick_push (tree, argvec, eltinit);
+	  eltinit = (build_special_member_call
+		     (NULL_TREE, complete_ctor_identifier, &argvec,
+		      elttype, LOOKUP_NORMAL, tf_warning_or_error));
+	  release_tree_vector (argvec);
+	  eltinit = cxx_eval_constant_expression
+	    (call, eltinit, allow_non_constant, addr, non_constant_p);
+	}
+      if (*non_constant_p && !allow_non_constant)
+	goto fail;
+      CONSTRUCTOR_APPEND_ELT (n, idx, eltinit);
+    }
+
+  if (!*non_constant_p)
+    {
+      init = build_constructor (TREE_TYPE (atype), n);
+      TREE_CONSTANT (init) = true;
+      return init;
+    }
+
+ fail:
+  VEC_free (constructor_elt, gc, n);
+  return init;
+}
+
+static tree
+cxx_eval_vec_init (const constexpr_call *call, tree t,
+		   bool allow_non_constant, bool addr,
+		   bool *non_constant_p)
+{
+  tree atype = TREE_TYPE (t);
+  tree init = VEC_INIT_EXPR_INIT (t);
+  tree r = cxx_eval_vec_init_1 (call, atype, init, allow_non_constant,
+				addr, non_constant_p);
+  if (*non_constant_p)
+    return t;
+  else
+    return r;
+}
+
+/* A less strict version of fold_indirect_ref_1, which requires cv-quals to
+   match.  We want to be less strict for simple *& folding; if we have a
+   non-const temporary that we access through a const pointer, that should
+   work.  We handle this here rather than change fold_indirect_ref_1
+   because we're dealing with things like ADDR_EXPR of INTEGER_CST which
+   don't really make sense outside of constant expression evaluation.  Also
+   we want to allow folding to COMPONENT_REF, which could cause trouble
+   with TBAA in fold_indirect_ref_1.  */
+
+static tree
+cxx_eval_indirect_ref (const constexpr_call *call, tree t,
+		       bool allow_non_constant, bool addr,
+		       bool *non_constant_p)
+{
+  tree orig_op0 = TREE_OPERAND (t, 0);
+  tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant,
+					   /*addr*/false, non_constant_p);
+  tree type, sub, subtype, r;
+  bool empty_base;
+
+  /* Don't VERIFY_CONSTANT here.  */
+  if (*non_constant_p)
+    return t;
+
+  type = TREE_TYPE (t);
+  sub = op0;
+  r = NULL_TREE;
+  empty_base = false;
+
+  STRIP_NOPS (sub);
+  subtype = TREE_TYPE (sub);
+  gcc_assert (POINTER_TYPE_P (subtype));
+
+  if (TREE_CODE (sub) == ADDR_EXPR)
+    {
+      tree op = TREE_OPERAND (sub, 0);
+      tree optype = TREE_TYPE (op);
+
+      if (same_type_ignoring_top_level_qualifiers_p (optype, type))
+	r = op;
+      /* Also handle conversion to an empty base class, which
+	 is represented with a NOP_EXPR.  */
+      else if (!addr && is_empty_class (type)
+	       && CLASS_TYPE_P (optype)
+	       && DERIVED_FROM_P (type, optype))
+	{
+	  r = op;
+	  empty_base = true;
+	}
+      /* *(foo *)&struct_with_foo_field => COMPONENT_REF */
+      else if (RECORD_OR_UNION_TYPE_P (optype))
+	{
+	  tree field = TYPE_FIELDS (optype);
+	  for (; field; field = DECL_CHAIN (field))
+	    if (TREE_CODE (field) == FIELD_DECL
+		&& integer_zerop (byte_position (field))
+		&& (same_type_ignoring_top_level_qualifiers_p
+		    (TREE_TYPE (field), type)))
+	      {
+		r = fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE);
+		break;
+	      }
+	}
+    }
+  else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
+	   && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+    {
+      tree op00 = TREE_OPERAND (sub, 0);
+      tree op01 = TREE_OPERAND (sub, 1);
+
+      STRIP_NOPS (op00);
+      if (TREE_CODE (op00) == ADDR_EXPR)
+	{
+	  tree op00type;
+	  op00 = TREE_OPERAND (op00, 0);
+	  op00type = TREE_TYPE (op00);
+
+	  /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */
+	  if (RECORD_OR_UNION_TYPE_P (op00type))
+	    {
+	      tree field = TYPE_FIELDS (op00type);
+	      for (; field; field = DECL_CHAIN (field))
+		if (TREE_CODE (field) == FIELD_DECL
+		    && tree_int_cst_equal (byte_position (field), op01)
+		    && (same_type_ignoring_top_level_qualifiers_p
+			(TREE_TYPE (field), type)))
+		  {
+		    r = fold_build3 (COMPONENT_REF, type, op00,
+				     field, NULL_TREE);
+		    break;
+		  }
+	    }
+	}
+    }
+
+  /* Let build_fold_indirect_ref handle the cases it does fine with.  */
+  if (r == NULL_TREE)
+    r = build_fold_indirect_ref (op0);
+  if (TREE_CODE (r) != INDIRECT_REF)
+    r = cxx_eval_constant_expression (call, r, allow_non_constant,
+				      addr, non_constant_p);
+  else if (TREE_CODE (sub) == ADDR_EXPR
+	   || TREE_CODE (sub) == POINTER_PLUS_EXPR)
+    {
+      gcc_assert (!same_type_ignoring_top_level_qualifiers_p
+		  (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
+      /* FIXME Mike Miller wants this to be OK.  */
+      if (!allow_non_constant)
+	error ("accessing value of %qE through a %qT glvalue in a "
+	       "constant expression", build_fold_indirect_ref (sub),
+	       TREE_TYPE (t));
+      *non_constant_p = true;
+      return t;
+    }
+
+  /* If we're pulling out the value of an empty base, make sure
+     that the whole object is constant and then return an empty
+     CONSTRUCTOR.  */
+  if (empty_base)
+    {
+      VERIFY_CONSTANT (r);
+      r = build_constructor (TREE_TYPE (t), NULL);
+      TREE_CONSTANT (r) = true;
+    }
+
+  if (TREE_CODE (r) == INDIRECT_REF && TREE_OPERAND (r, 0) == orig_op0)
+    return t;
+  return r;
+}
+
+/* Attempt to reduce the expression T to a constant value.
+   On failure, issue diagnostic and return error_mark_node.  */
+/* FIXME unify with c_fully_fold */
+
+static tree
+cxx_eval_constant_expression (const constexpr_call *call, tree t,
+			      bool allow_non_constant, bool addr,
+			      bool *non_constant_p)
+{
+  tree r = t;
+
+  if (t == error_mark_node)
+    {
+      *non_constant_p = true;
+      return t;
+    }
+  if (CONSTANT_CLASS_P (t))
+    {
+      if (TREE_CODE (t) == PTRMEM_CST)
+	t = cplus_expand_constant (t);
+      return t;
+    }
+  if (TREE_CODE (t) != NOP_EXPR
+      && reduced_constant_expression_p (t))
+    return fold (t);
+
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+      if (addr)
+	return t;
+      /* else fall through. */
+    case CONST_DECL:
+      r = integral_constant_value (t);
+      if (TREE_CODE (r) == TARGET_EXPR
+	  && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
+	r = TARGET_EXPR_INITIAL (r);
+      if (DECL_P (r))
+	{
+	  if (!allow_non_constant)
+	    error ("%qD cannot appear in a constant expression", r);
+	  *non_constant_p = true;
+	}
+      break;
+
+    case FUNCTION_DECL:
+    case LABEL_DECL:
+      return t;
+
+    case PARM_DECL:
+      if (call && DECL_CONTEXT (t) == call->fundef->decl)
+	r = lookup_parameter_binding (call, t);
+      else if (addr)
+	/* Defer in case this is only used for its type.  */;
+      else
+	{
+	  if (!allow_non_constant)
+	    error ("%qE is not a constant expression", t);
+	  *non_constant_p = true;
+	}
+      break;
+
+    case CALL_EXPR:
+    case AGGR_INIT_EXPR:
+      r = cxx_eval_call_expression (call, t, allow_non_constant, addr,
+				    non_constant_p);
+      break;
+
+    case TARGET_EXPR:
+    case INIT_EXPR:
+      /* Pass false for 'addr' because these codes indicate
+	 initialization of a temporary.  */
+      r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+					allow_non_constant, false,
+					non_constant_p);
+      if (!*non_constant_p)
+	/* Adjust the type of the result to the type of the temporary.  */
+	r = adjust_temp_type (TREE_TYPE (t), r);
+      break;
+
+    case SCOPE_REF:
+      r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+					allow_non_constant, addr,
+					non_constant_p);
+      break;
+
+    case RETURN_EXPR:
+    case NON_LVALUE_EXPR:
+    case TRY_CATCH_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case MUST_NOT_THROW_EXPR:
+    case SAVE_EXPR:
+      r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+					allow_non_constant, addr,
+					non_constant_p);
+      break;
+
+      /* These differ from cxx_eval_unary_expression in that this doesn't
+	 check for a constant operand or result; an address can be
+	 constant without its operand being, and vice versa.  */
+    case INDIRECT_REF:
+      r = cxx_eval_indirect_ref (call, t, allow_non_constant, addr,
+				 non_constant_p);
+      break;
+
+    case ADDR_EXPR:
+      {
+	tree oldop = TREE_OPERAND (t, 0);
+	tree op = cxx_eval_constant_expression (call, oldop,
+						allow_non_constant,
+						/*addr*/true,
+						non_constant_p);
+	/* Don't VERIFY_CONSTANT here.  */
+	if (*non_constant_p)
+	  return t;
+	/* This function does more aggressive folding than fold itself.  */
+	r = build_fold_addr_expr_with_type (op, TREE_TYPE (t));
+	if (TREE_CODE (r) == ADDR_EXPR && TREE_OPERAND (r, 0) == oldop)
+	  return t;
+	break;
+      }
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case FIXED_CONVERT_EXPR:
+      r = cxx_eval_unary_expression (call, t, allow_non_constant, addr,
+				     non_constant_p);
+      break;
+
+    case COMPOUND_EXPR:
+      {
+	/* check_return_expr sometimes wraps a TARGET_EXPR in a
+	   COMPOUND_EXPR; don't get confused.  Also handle EMPTY_CLASS_EXPR
+	   introduced by build_call_a.  */
+	tree op0 = TREE_OPERAND (t, 0);
+	tree op1 = TREE_OPERAND (t, 1);
+	STRIP_NOPS (op1);
+	if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
+	    || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
+	  r = cxx_eval_constant_expression (call, op0, allow_non_constant,
+					    addr, non_constant_p);
+	else
+	  goto binary;
+      }
+      break;
+
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case RANGE_EXPR:
+    case COMPLEX_EXPR:
+    binary:
+      r = cxx_eval_binary_expression (call, t, allow_non_constant, addr,
+				      non_constant_p);
+      break;
+
+      /* fold can introduce non-IF versions of these; still treat them as
+	 short-circuiting.  */
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+      r = cxx_eval_logical_expression (call, t, boolean_false_node,
+				       boolean_true_node,
+				       allow_non_constant, addr,
+				       non_constant_p);
+      break;
+
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+      r = cxx_eval_logical_expression (call, t, boolean_true_node,
+				       boolean_false_node,
+				       allow_non_constant, addr,
+				       non_constant_p);
+      break;
+
+    case ARRAY_REF:
+      r = cxx_eval_array_reference (call, t, allow_non_constant, addr,
+				    non_constant_p);
+      break;
+
+    case COMPONENT_REF:
+      r = cxx_eval_component_reference (call, t, allow_non_constant, addr,
+					non_constant_p);
+      break;
+
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      r = cxx_eval_conditional_expression (call, t, allow_non_constant, addr,
+					   non_constant_p);
+      break;
+
+    case CONSTRUCTOR:
+      r = cxx_eval_bare_aggregate (call, t, allow_non_constant, addr,
+				   non_constant_p);
+      break;
+
+    case VEC_INIT_EXPR:
+      /* We can get this in a defaulted constructor for a class with a
+	 non-static data member of array type.  Either the initializer will
+	 be NULL, meaning default-initialization, or it will be an lvalue
+	 or xvalue of the same type, meaning direct-initialization from the
+	 corresponding member.  */
+      r = cxx_eval_vec_init (call, t, allow_non_constant, addr,
+			     non_constant_p);
+      break;
+
+    case CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+    case NOP_EXPR:
+      {
+	tree oldop = TREE_OPERAND (t, 0);
+	tree op = oldop;
+	tree to = TREE_TYPE (t);
+	tree source = TREE_TYPE (op);
+        if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (to)
+	    && !(TREE_CODE (op) == COMPONENT_REF
+		 && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (op, 0)))))
+          {
+            if (!allow_non_constant)
+              error ("conversion of expression %qE of pointer type "
+                     "cannot yield a constant expression", op);
+	    *non_constant_p = true;
+	    return t;
+          }
+	op = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+					   allow_non_constant, addr,
+					   non_constant_p);
+	if (*non_constant_p)
+	  return t;
+	if (op == oldop)
+	  /* We didn't fold at the top so we could check for ptr-int
+	     conversion.  */
+	  return fold (t);
+	r = fold_build1 (TREE_CODE (t), to, op);
+      }
+      break;
+
+    case EMPTY_CLASS_EXPR:
+      /* This is good enough for a function argument that might not get
+	 used, and they can't do anything with it, so just return it.  */
+      return t;
+
+    case LAMBDA_EXPR:
+    case DYNAMIC_CAST_EXPR:
+    case PSEUDO_DTOR_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+    case DELETE_EXPR:
+    case VEC_DELETE_EXPR:
+    case THROW_EXPR:
+    case MODIFY_EXPR:
+    case MODOP_EXPR:
+      /* GCC internal stuff.  */
+    case VA_ARG_EXPR:
+    case OBJ_TYPE_REF:
+    case WITH_CLEANUP_EXPR:
+    case STATEMENT_LIST:
+    case BIND_EXPR:
+    case NON_DEPENDENT_EXPR:
+    case BASELINK:
+    case EXPR_STMT:
+      if (!allow_non_constant)
+        error_at (EXPR_LOC_OR_HERE (t),
+		  "expression %qE is not a constant-expression", t);
+      *non_constant_p = true;
+      break;
+
+    default:
+      internal_error ("unexpected expression %qE of kind %s", t,
+		      tree_code_name[TREE_CODE (t)]);
+      *non_constant_p = true;
+      break;
+    }
+
+  if (r == error_mark_node)
+    *non_constant_p = true;
+
+  if (*non_constant_p)
+    return t;
+  else
+    return r;
+}
+
+static tree
+cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
+{
+  bool non_constant_p = false;
+  tree r = cxx_eval_constant_expression (NULL, t, allow_non_constant,
+					 false, &non_constant_p);
+
+  if (!non_constant_p && !reduced_constant_expression_p (r))
+    {
+      if (!allow_non_constant)
+	error ("%qE is not a constant expression", t);
+      non_constant_p = true;
+    }
+
+  if (non_constant_p && !allow_non_constant)
+    return error_mark_node;
+  else if (non_constant_p && TREE_CONSTANT (t))
+    {
+      /* This isn't actually constant, so unset TREE_CONSTANT.  */
+      if (EXPR_P (t) || TREE_CODE (t) == CONSTRUCTOR)
+	r = copy_node (t);
+      else
+	r = build_nop (TREE_TYPE (t), t);
+      TREE_CONSTANT (r) = false;
+      return r;
+    }
+  else if (non_constant_p || r == t)
+    return t;
+  else if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
+    {
+      if (TREE_CODE (t) == TARGET_EXPR
+	  && TARGET_EXPR_INITIAL (t) == r)
+	return t;
+      else
+	{
+	  r = get_target_expr (r);
+	  TREE_CONSTANT (r) = true;
+	  return r;
+	}
+    }
+  else
+    return r;
+}
+
+/* If T represents a constant expression returns its reduced value.
+   Otherwise return error_mark_node.  If T is dependent, then
+   return NULL.  */
+
+tree
+cxx_constant_value (tree t)
+{
+  return cxx_eval_outermost_constant_expr (t, false);
+}
+
+/* If T is a constant expression, returns its reduced value.
+   Otherwise, if T does not have TREE_CONSTANT set, returns T.
+   Otherwise, returns a version of T without TREE_CONSTANT.  */
+
+tree
+maybe_constant_value (tree t)
+{
+  tree r;
+
+  if (type_dependent_expression_p (t)
+      /* FIXME shouldn't check value-dependence first; see comment before
+	 value_dependent_expression_p.  */
+      || value_dependent_expression_p (t))
+    return t;
+
+  r = cxx_eval_outermost_constant_expr (t, true);
+#ifdef ENABLE_CHECKING
+  /* cp_tree_equal looks through NOPs, so allow them.  */
+  gcc_assert (r == t
+	      || CONVERT_EXPR_P (t)
+	      || (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
+	      || !cp_tree_equal (r, t));
+#endif
+  return r;
+}
+
+/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
+   than wrapped in a TARGET_EXPR.  */
+
+tree
+maybe_constant_init (tree t)
+{
+  t = maybe_constant_value (t);
+  if (TREE_CODE (t) == TARGET_EXPR)
+    {
+      tree init = TARGET_EXPR_INITIAL (t);
+      if (TREE_CODE (init) == CONSTRUCTOR
+	  && TREE_CONSTANT (init))
+	t = init;
+    }
+  return t;
+}
+
 /* Return true if the object referred to by REF has automatic or thread
    local storage.  */
commit 0b11bb56b4b96bd71492bc5f7fd7c4f91687634f
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 27 10:26:38 2010 -0400

    	* call.c (null_ptr_cst_p): Use maybe_constant_value.
    	(set_up_extended_ref_temp): Support constant initialization.
    	(initialize_reference): Adjust.
    	* class.c (check_bitfield_decl): Use cxx_constant_value.
    	* cvt.c (ocp_convert): Don't use integral_constant_value when
    	converting to class type.
    	* decl.c (finish_case_label): Use maybe_constant_value.
    	(build_init_list_var_init): Support constant initialization.
    	(check_initializer): Likewise.  Reorganize.
    	(cp_finish_decl): Likewise.
    	(expand_static_init): Likewise.
    	(compute_array_index_type): Use maybe_constant_value.
    	Add complain parm.
    	(create_array_type_for_decl, grokdeclarator): Pass it.
    	(build_enumerator): Use cxx_constant_value.
    	* decl2.c (grokfield): Use maybe_constant_init.
    	* except.c (check_noexcept_r): Handle constexpr.
    	(build_noexcept_spec): Use maybe_constant_value.
    	* init.c (expand_default_init): Support constant initialization.
    	(build_vec_init): Likewise.
    	(constant_value_1): Adjust.
    	(build_new_1): Adjust.
    	* parser.c (cp_parser_constant_expression): Allow non-integral
    	in C++0x mode.
    	(cp_parser_direct_declarator): Don't fold yet in C++0x mode.
    	(cp_parser_initializer_clause): Toss folded result if non-constant.
    	* pt.c (fold_decl_constant_value): Remove.
    	(convert_nontype_argument): Use maybe_constant_value.  Give clearer
    	error about overflow.
    	(tsubst): Move array bounds handling into compute_array_index_type.
    	(value_dependent_expression_p): Handle constant CALL_EXPR.
    	* semantics.c (finish_static_assert): Use maybe_constant_value.
    	(ensure_literal_type_for_constexpr_object): Make sure type is complete.
    	(potential_constant_expression): Use maybe_constant_value.
    	* tree.c (cast_valid_in_integral_constant_expression_p): Any cast
    	is potentially valid in C++0x.
    	* typeck2.c (store_init_value): Handle constant init.
    	(check_narrowing): Use maybe_constant_value.
    	(build_functional_cast): Set TREE_CONSTANT on literal T().
    	* cp-tree.h (DECL_INTEGRAL_CONSTANT_VAR_P): Remove.
    	(LOOKUP_ALREADY_DIGESTED): New.
    	(compute_array_index_type): Adjust prototype.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 204fda5..a1c8682 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -466,15 +466,24 @@ null_ptr_cst_p (tree t)
      A null pointer constant is an integral constant expression
      (_expr.const_) rvalue of integer type that evaluates to zero or
      an rvalue of type std::nullptr_t. */
-  t = integral_constant_value (t);
-  if (t == null_node
-      || NULLPTR_TYPE_P (TREE_TYPE (t)))
+  if (NULLPTR_TYPE_P (TREE_TYPE (t)))
     return true;
-  if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t))
+  if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)))
     {
-      STRIP_NOPS (t);
-      if (!TREE_OVERFLOW (t))
-	return true;
+      if (cxx_dialect >= cxx0x)
+	{
+	  t = fold_non_dependent_expr (t);
+	  t = maybe_constant_value (t);
+	  if (TREE_CONSTANT (t) && integer_zerop (t))
+	    return true;
+	}
+      else
+	{
+	  t = integral_constant_value (t);
+	  STRIP_NOPS (t);
+	  if (integer_zerop (t) && !TREE_OVERFLOW (t))
+	    return true;
+	}
     }
   return false;
 }
@@ -7907,9 +7916,32 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
      VAR.  */
   if (TREE_CODE (expr) != TARGET_EXPR)
     expr = get_target_expr (expr);
-  /* Create the INIT_EXPR that will initialize the temporary
-     variable.  */
-  init = build2 (INIT_EXPR, type, var, expr);
+
+  /* If the initializer is constant, put it in DECL_INITIAL so we get
+     static initialization and use in constant expressions.  */
+  init = maybe_constant_init (expr);
+  if (TREE_CONSTANT (init))
+    {
+      if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type))
+	{
+	  /* 5.19 says that a constant expression can include an
+	     lvalue-rvalue conversion applied to "a glvalue of literal type
+	     that refers to a non-volatile temporary object initialized
+	     with a constant expression".  Rather than try to communicate
+	     that this VAR_DECL is a temporary, just mark it constexpr.
+
+	     Currently this is only useful for initializer_list temporaries,
+	     since reference vars can't appear in constant expressions.  */
+	  DECL_DECLARED_CONSTEXPR_P (var) = true;
+	  TREE_CONSTANT (var) = true;
+	}
+      DECL_INITIAL (var) = init;
+      init = NULL_TREE;
+    }
+  else
+    /* Create the INIT_EXPR that will initialize the temporary
+       variable.  */
+    init = build2 (INIT_EXPR, type, var, expr);
   if (at_function_scope_p ())
     {
       add_decl_expr (var);
@@ -8067,7 +8099,8 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
 					build_pointer_type (base_conv_type),
 					/*check_access=*/true,
 					/*nonnull=*/true, complain);
-	      expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
+	      if (init)
+		expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
 	    }
 	  else
 	    /* Take the address of EXPR.  */
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 1c9fac1..217450c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2802,7 +2802,7 @@ check_bitfield_decl (tree field)
       STRIP_NOPS (w);
 
       /* detect invalid field size.  */
-      w = integral_constant_value (w);
+      w = cxx_constant_value (w);
 
       if (TREE_CODE (w) != INTEGER_CST)
 	{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 96fefae..e408ef7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2207,23 +2207,6 @@ struct GTY((variable_size)) lang_decl {
 #define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE) \
   (TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE)))
 
-/* Nonzero for a VAR_DECL that can be used in an integral constant
-   expression.
-
-      [expr.const]
-
-      An integral constant-expression can only involve ... const
-      variables of static or enumeration types initialized with
-      constant expressions ...
-
-   The standard does not require that the expression be non-volatile.
-   G++ implements the proposed correction in DR 457.  */
-#define DECL_INTEGRAL_CONSTANT_VAR_P(NODE)		\
-  (TREE_CODE (NODE) == VAR_DECL				\
-   && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (NODE))	\
-   && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (NODE))	\
-   && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (NODE))
-
 /* Nonzero if the DECL was initialized in the class definition itself,
    rather than outside the class.  This is used for both static member
    VAR_DECLS, and FUNCTION_DECLS that are defined in the class.  */
@@ -4235,6 +4218,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
    another mechanism.  Exiting early also avoids problems with trying
    to perform argument conversions when the class isn't complete yet.  */
 #define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
+/* Used in calls to store_init_value to suppress its usual call to
+   digest_init.  */
+#define LOOKUP_ALREADY_DIGESTED (LOOKUP_SPECULATIVE << 1)
 
 #define LOOKUP_NAMESPACES_ONLY(F)  \
   (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -4826,7 +4812,7 @@ extern tree static_fn_type			(tree);
 extern void revert_static_member_fn		(tree);
 extern void fixup_anonymous_aggr		(tree);
 extern int check_static_variable_definition	(tree, tree);
-extern tree compute_array_index_type		(tree, tree);
+extern tree compute_array_index_type		(tree, tree, tsubst_flags_t);
 extern tree check_default_argument		(tree, tree);
 typedef int (*walk_namespaces_fn)		(tree, void *);
 extern int walk_namespaces			(walk_namespaces_fn,
@@ -5258,6 +5244,7 @@ extern tree ensure_literal_type_for_constexpr_object (tree);
 extern tree cxx_constant_value (tree);
 extern tree maybe_constant_value (tree);
 extern tree maybe_constant_init (tree);
+extern bool is_sub_constant_expr (tree);
 extern bool reduced_constant_expression_p (tree);
 
 enum {
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 95d0ab9..d2d6f4a 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -609,7 +609,10 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
       return error_mark_node;
     }
 
-  e = integral_constant_value (e);
+  /* FIXME remove when moving to c_fully_fold model.  */
+  /* FIXME do we still need this test?  */
+  if (!CLASS_TYPE_P (type))
+    e = integral_constant_value (e);
   if (error_operand_p (e))
     return error_mark_node;
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index de6f0c4..fb5ca7f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2936,9 +2936,9 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
     return error_mark_node;
 
   if (low_value)
-    low_value = decl_constant_value (low_value);
+    low_value = cxx_constant_value (low_value);
   if (high_value)
-    high_value = decl_constant_value (high_value);
+    high_value = cxx_constant_value (high_value);
 
   r = c_add_case_label (loc, switch_stack->cases, cond,
 			SWITCH_STMT_TYPE (switch_stack->switch_stmt),
@@ -4530,7 +4530,8 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
    grok_reference_init.  */
 
 static tree
-build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
+build_init_list_var_init (tree decl, tree type, tree init, tree *array_init,
+			  tree *cleanup)
 {
   tree aggr_init, array, arrtype;
   init = perform_implicit_conversion (type, init, tf_warning_or_error);
@@ -4538,8 +4539,6 @@ build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
     return error_mark_node;
 
   aggr_init = TARGET_EXPR_INITIAL (init);
-  init = build2 (INIT_EXPR, type, decl, init);
-
   array = AGGR_INIT_EXPR_ARG (aggr_init, 1);
   arrtype = TREE_TYPE (array);
   STRIP_NOPS (array);
@@ -4549,12 +4548,10 @@ build_init_list_var_init (tree decl, tree type, tree init, tree *cleanup)
      static variable and we don't need to do anything here.  */
   if (decl && TREE_CODE (array) == TARGET_EXPR)
     {
-      tree subinit;
-      tree var = set_up_extended_ref_temp (decl, array, cleanup, &subinit);
+      tree var = set_up_extended_ref_temp (decl, array, cleanup, array_init);
       var = build_address (var);
       var = convert (arrtype, var);
       AGGR_INIT_EXPR_ARG (aggr_init, 1) = var;
-      init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init);
     }
   return init;
 }
@@ -5250,6 +5247,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
 {
   tree type = TREE_TYPE (decl);
   tree init_code = NULL;
+  tree extra_init = NULL_TREE;
   tree core_type;
 
   /* Things that are going to be initialized need to have complete
@@ -5304,16 +5302,21 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
       gcc_assert (init != NULL_TREE);
       init = NULL_TREE;
     }
-  else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
+  else if (!init && DECL_REALLY_EXTERN (decl))
+    ;
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
     init = grok_reference_init (decl, type, init, cleanup);
-  else if (init)
+  else if (init || TYPE_NEEDS_CONSTRUCTING (type))
     {
+      if (!init)
+	check_for_uninitialized_const_var (decl);
       /* Do not reshape constructors of vectors (they don't need to be
 	 reshaped.  */
-      if (BRACE_ENCLOSED_INITIALIZER_P (init))
+      else if (BRACE_ENCLOSED_INITIALIZER_P (init))
 	{
 	  if (is_std_init_list (type))
-	    return build_init_list_var_init (decl, type, init, cleanup);
+	    init = build_init_list_var_init (decl, type, init,
+					     &extra_init, cleanup);
 	  else if (TYPE_NON_AGGREGATE_CLASS (type))
 	    {
 	      /* Don't reshape if the class has constructors.  */
@@ -5340,9 +5343,46 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
 
       if (TYPE_NEEDS_CONSTRUCTING (type)
 	  || (CLASS_TYPE_P (type)
-	      && !BRACE_ENCLOSED_INITIALIZER_P (init)))
-	return build_aggr_init_full_exprs (decl, init, flags);
-      else if (TREE_CODE (init) != TREE_VEC)
+	      && !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
+	{
+	  init_code = build_aggr_init_full_exprs (decl, init, flags);
+
+	  /* If this is a constexpr initializer, expand_default_init will
+	     have returned an INIT_EXPR rather than a CALL_EXPR.  In that
+	     case, pull the initializer back out and pass it down into
+	     store_init_value.  */
+	  while (TREE_CODE (init_code) == EXPR_STMT
+		 || TREE_CODE (init_code) == CONVERT_EXPR)
+	    init_code = TREE_OPERAND (init_code, 0);
+	  if (TREE_CODE (init_code) == INIT_EXPR)
+	    {
+	      init = TREE_OPERAND (init_code, 1);
+	      init_code = NULL_TREE;
+	      /* Don't call digest_init; it's unnecessary and will complain
+		 about aggregate initialization of non-aggregate classes.  */
+	      flags |= LOOKUP_ALREADY_DIGESTED;
+	    }
+	  else if (DECL_DECLARED_CONSTEXPR_P (decl))
+	    {
+	      /* Declared constexpr, but no suitable initializer; massage
+		 init appropriately so we can pass it into store_init_value
+		 for the error.  */
+	      if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
+		init = finish_compound_literal (type, init);
+	      else if (CLASS_TYPE_P (type)
+		       && (!init || TREE_CODE (init) == TREE_LIST))
+		{
+		  init = build_functional_cast (type, init, tf_none);
+		  if (init != error_mark_node)
+		    TARGET_EXPR_DIRECT_INIT_P (init) = true;
+		}
+	      init_code = NULL_TREE;
+	    }
+	  else
+	    init = NULL_TREE;
+	}
+
+      if (init && TREE_CODE (init) != TREE_VEC)
 	{
 	  init_code = store_init_value (decl, init, flags);
 	  if (pedantic && TREE_CODE (type) == ARRAY_TYPE
@@ -5354,28 +5394,39 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
 	  init = NULL;
 	}
     }
-  else if (DECL_EXTERNAL (decl))
-    ;
-  else if (TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type))
+  else
     {
-      check_for_uninitialized_const_var (decl);
-      return build_aggr_init_full_exprs (decl, init, flags);
-    }
-  else if (MAYBE_CLASS_TYPE_P (core_type = strip_array_types (type)))
-    {
-      if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
-	  || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
+      if (CLASS_TYPE_P (core_type = strip_array_types (type))
+	  && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
+	      || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type)))
 	diagnose_uninitialized_cst_or_ref_member (core_type, /*using_new=*/false,
 						  /*complain=*/true);
 
       check_for_uninitialized_const_var (decl);
     }
-  else
-    check_for_uninitialized_const_var (decl);
 
   if (init && init != error_mark_node)
     init_code = build2 (INIT_EXPR, type, decl, init);
 
+  if (extra_init)
+    init_code = add_stmt_to_compound (extra_init, init_code);
+
+  if (init_code && DECL_IN_AGGR_P (decl))
+    {
+      static int explained = 0;
+
+      if (cxx_dialect < cxx0x)
+	error ("initializer invalid for static member with constructor");
+      else
+	error ("non-constant in-class initialization invalid for static "
+	       "member %qD", decl);
+      if (!explained)
+	{
+	  error ("(an out of class initialization is required)");
+	  explained = 1;
+	}
+    }
+
   return init_code;
 }
 
@@ -5746,7 +5797,22 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	    DECL_INITIAL (decl) = NULL_TREE;
 	}
     }
-    
+
+  if (init && TREE_CODE (decl) == VAR_DECL)
+    {
+      DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
+      /* FIXME we rely on TREE_CONSTANT below; basing that on
+	 init_const_expr_p is probably wrong for C++0x.  */
+      if (init_const_expr_p)
+	{
+	  /* Set these flags now for C++98 templates.  We'll update the
+	     flags in store_init_value for instantiations and C++0x.  */
+	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
+	  if (decl_maybe_constant_var_p (decl))
+	    TREE_CONSTANT (decl) = 1;
+	}
+    }
+
   if (processing_template_decl)
     {
       bool type_dependent_p;
@@ -5763,22 +5829,16 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  DECL_INITIAL (decl) = NULL_TREE;
 	}
 
-      if (init && init_const_expr_p && TREE_CODE (decl) == VAR_DECL)
-	{
-	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
-	  if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
-	    TREE_CONSTANT (decl) = 1;
-	}
-
       /* Generally, initializers in templates are expanded when the
-	 template is instantiated.  But, if DECL is an integral
-	 constant static data member, then it can be used in future
-	 integral constant expressions, and its value must be
-	 available. */
+	 template is instantiated.  But, if DECL is a variable constant
+	 then it can be used in future constant expressions, so its value
+	 must be available. */
       if (!(init
 	    && DECL_CLASS_SCOPE_P (decl)
-	    && DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+	    /* We just set TREE_CONSTANT appropriately; see above.  */
+	    && TREE_CONSTANT (decl)
 	    && !type_dependent_p
+	    /* FIXME non-value-dependent constant expression  */
 	    && !value_dependent_init_p (init)))
 	{
 	  if (init)
@@ -5892,16 +5952,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 		error ("Java object %qD not allocated with %<new%>", decl);
 	      init = NULL_TREE;
 	    }
-	  if (init)
-	    {
-	      DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
-	      if (init_const_expr_p)
-		{
-		  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
-		  if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
-		    TREE_CONSTANT (decl) = 1;
-		}
-	    }
 	  init = check_initializer (decl, init, flags, &cleanup);
 	  /* Thread-local storage cannot be dynamically initialized.  */
 	  if (DECL_THREAD_LOCAL_P (decl) && init)
@@ -6407,9 +6457,8 @@ expand_static_init (tree decl, tree init)
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
   gcc_assert (TREE_STATIC (decl));
 
-  /* Some variables require no initialization.  */
+  /* Some variables require no dynamic initialization.  */
   if (!init
-      && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
       && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
     return;
 
@@ -7417,36 +7466,67 @@ check_static_variable_definition (tree decl, tree type)
    name of the thing being declared.  */
 
 tree
-compute_array_index_type (tree name, tree size)
+compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 {
   tree type;
   tree itype;
+  tree osize = size;
   tree abi_1_itype = NULL_TREE;
 
   if (error_operand_p (size))
     return error_mark_node;
 
   type = TREE_TYPE (size);
-  /* The array bound must be an integer type.  */
-  if (!dependent_type_p (type) && !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
+  /* type_dependent_expression_p? */
+  if (!dependent_type_p (type))
     {
-      if (name)
-	error ("size of array %qD has non-integral type %qT", name, type);
+      mark_rvalue_use (size);
+
+      if (cxx_dialect < cxx0x && TREE_CODE (size) == NOP_EXPR
+	  && TREE_SIDE_EFFECTS (size))
+	/* In C++98, we mark a non-constant array bound with a magic
+	   NOP_EXPR with TREE_SIDE_EFFECTS; don't fold in that case.  */;
       else
-	error ("size of array has non-integral type %qT", type);
-      size = integer_one_node;
-      type = TREE_TYPE (size);
+	{
+	  size = fold_non_dependent_expr (size);
+
+	  if (CLASS_TYPE_P (type)
+	      && CLASSTYPE_LITERAL_P (type))
+	    {
+	      size = build_expr_type_conversion (WANT_INT, size, true);
+	      if (size == error_mark_node)
+		return error_mark_node;
+	      type = TREE_TYPE (size);
+	    }
+
+	  size = maybe_constant_value (size);
+	}
+
+      if (error_operand_p (size))
+	return error_mark_node;
+
+      /* The array bound must be an integer type.  */
+      if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type))
+	{
+	  if (!(complain & tf_error))
+	    return error_mark_node;
+	  if (name)
+	    error ("size of array %qD has non-integral type %qT", name, type);
+	  else
+	    error ("size of array has non-integral type %qT", type);
+	  size = integer_one_node;
+	  type = TREE_TYPE (size);
+	}
     }
 
   /* A type is dependent if it is...an array type constructed from any
      dependent type or whose size is specified by a constant expression
      that is value-dependent.  */
   /* We can only call value_dependent_expression_p on integral constant
-     expressions; the parser adds a dummy NOP_EXPR with TREE_SIDE_EFFECTS
-     set if this isn't one.  */
+     expressions; treat non-constant expressions as dependent, too.  */
   if (processing_template_decl
       && (dependent_type_p (type)
-	  || TREE_SIDE_EFFECTS (size) || value_dependent_expression_p (size)))
+	  || !TREE_CONSTANT (size) || value_dependent_expression_p (size)))
     {
       /* We cannot do any checking for a SIZE that isn't known to be
 	 constant. Just build the index type and mark that it requires
@@ -7467,17 +7547,7 @@ compute_array_index_type (tree name, tree size)
        would have, but with TYPE_CANONICAL set to the "right"
        value that the current ABI would provide. */
     abi_1_itype = build_index_type (build_min (MINUS_EXPR, sizetype,
-					       size, integer_one_node));
-
-  /* The size might be the result of a cast.  */
-  STRIP_TYPE_NOPS (size);
-
-  size = mark_rvalue_use (size);
-
-  /* It might be a const variable or enumeration constant.  */
-  size = integral_constant_value (size);
-  if (error_operand_p (size))
-    return error_mark_node;
+					       osize, integer_one_node));
 
   /* Normally, the array-bound will be a constant.  */
   if (TREE_CODE (size) == INTEGER_CST)
@@ -7489,24 +7559,37 @@ compute_array_index_type (tree name, tree size)
       /* An array must have a positive number of elements.  */
       if (INT_CST_LT (size, integer_zero_node))
 	{
+	  if (!(complain & tf_error))
+	    return error_mark_node;
 	  if (name)
 	    error ("size of array %qD is negative", name);
 	  else
 	    error ("size of array is negative");
 	  size = integer_one_node;
 	}
-      /* As an extension we allow zero-sized arrays.  We always allow
-	 them in system headers because glibc uses them.  */
-      else if (integer_zerop (size) && !in_system_header)
+      /* As an extension we allow zero-sized arrays.  */
+      else if (integer_zerop (size))
 	{
-	  if (name)
+	  if (!(complain & tf_error))
+	    /* We must fail if performing argument deduction (as
+	       indicated by the state of complain), so that
+	       another substitution can be found.  */
+	    return error_mark_node;
+	  else if (in_system_header)
+	    /* Allow them in system headers because glibc uses them.  */;
+	  else if (name)
 	    pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array %qD", name);
 	  else
 	    pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array");
 	}
     }
-  else if (TREE_CONSTANT (size))
+  else if (TREE_CONSTANT (size)
+	   /* We don't allow VLAs at non-function scopes, or during
+	      tentative template substitution.  */
+	   || !at_function_scope_p () || !(complain & tf_error))
     {
+      if (!(complain & tf_error))
+	return error_mark_node;
       /* `(int) &fn' is not a valid array bound.  */
       if (name)
 	error ("size of array %qD is not an integral constant-expression",
@@ -7562,6 +7645,8 @@ compute_array_index_type (tree name, tree size)
       else if (TREE_CODE (itype) == INTEGER_CST
 	       && TREE_OVERFLOW (itype))
 	{
+	  if (!(complain & tf_error))
+	    return error_mark_node;
 	  error ("overflow in array dimension");
 	  TREE_OVERFLOW (itype) = 0;
 	}
@@ -7673,7 +7758,7 @@ create_array_type_for_decl (tree name, tree type, tree size)
 
   /* Figure out the index type for the array.  */
   if (size)
-    itype = compute_array_index_type (name, size);
+    itype = compute_array_index_type (name, size, tf_warning_or_error);
 
   /* [dcl.array]
      T is called the array element type; this type shall not be [...] an
@@ -9411,7 +9496,8 @@ grokdeclarator (const cp_declarator *declarator,
 	if (!staticp && TREE_CODE (type) == ARRAY_TYPE
 	    && TYPE_DOMAIN (type) == NULL_TREE)
 	  {
-	    tree itype = compute_array_index_type (dname, integer_zero_node);
+	    tree itype = compute_array_index_type (dname, integer_zero_node,
+						   tf_warning_or_error);
 	    type = build_cplus_array_type (TREE_TYPE (type), itype);
 	  }
 
@@ -11732,7 +11818,7 @@ build_enumerator (tree name, tree value, tree enumtype, location_t loc)
       /* Validate and default VALUE.  */
       if (value != NULL_TREE)
 	{
-	  value = integral_constant_value (value);
+	  value = cxx_constant_value (value);
 
 	  if (TREE_CODE (value) == INTEGER_CST)
 	    {
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 3f492bb..0003601 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -923,8 +923,7 @@ grokfield (const cp_declarator *declarator,
 	{
 	  if (TREE_CODE (init) == CONSTRUCTOR)
 	    init = digest_init (TREE_TYPE (value), init);
-	  else
-	    init = integral_constant_value (init);
+	  init = maybe_constant_init (init);
 
 	  if (init != error_mark_node && !TREE_CONSTANT (init))
 	    {
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index cf8a210..f02096e 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1054,15 +1054,20 @@ check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
 
       STRIP_NOPS (fn);
       if (TREE_CODE (fn) == ADDR_EXPR)
+	fn = TREE_OPERAND (fn, 0);
+      if (TREE_CODE (fn) == FUNCTION_DECL)
 	{
 	  /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast,
 	     and for C library functions known not to throw.  */
-	  fn = TREE_OPERAND (fn, 0);
-	  if (TREE_CODE (fn) == FUNCTION_DECL
-	      && DECL_EXTERN_C_P (fn)
+	  if (DECL_EXTERN_C_P (fn)
 	      && (DECL_ARTIFICIAL (fn)
 		  || nothrow_libfn_p (fn)))
 	    return TREE_NOTHROW (fn) ? NULL_TREE : fn;
+	  /* A call to a constexpr function is noexcept if the call
+	     is a constant expression.  */
+	  if (DECL_DECLARED_CONSTEXPR_P (fn)
+	      && is_sub_constant_expr (t))
+	    return NULL_TREE;
 	}
       if (!TYPE_NOTHROW_P (type))
 	return fn;
@@ -1195,9 +1200,15 @@ type_throw_all_p (const_tree type)
 tree
 build_noexcept_spec (tree expr, int complain)
 {
-  expr = perform_implicit_conversion_flags (boolean_type_node, expr,
-					    complain,
-					    LOOKUP_NORMAL);
+  /* This isn't part of the signature, so don't bother trying to evaluate
+     it until instantiation.  */
+  if (!processing_template_decl)
+    {
+      expr = cxx_constant_value (expr);
+      expr = perform_implicit_conversion_flags (boolean_type_node, expr,
+						complain,
+						LOOKUP_NORMAL);
+    }
   if (expr == boolean_true_node)
     return noexcept_true_spec;
   else if (expr == boolean_false_node)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3a6e2e7..d632816 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1440,8 +1440,20 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
   if (parms != NULL)
     release_tree_vector (parms);
 
+  if (exp == true_exp && TREE_CODE (rval) == CALL_EXPR)
+    {
+      tree fn = get_callee_fndecl (rval);
+      if (DECL_DECLARED_CONSTEXPR_P (fn))
+	{
+	  tree e = maybe_constant_value (rval);
+	  if (TREE_CONSTANT (e))
+	    rval = build2 (INIT_EXPR, type, exp, e);
+	}
+    }
+
+  /* FIXME put back convert_to_void?  */
   if (TREE_SIDE_EFFECTS (rval))
-    finish_expr_stmt (convert_to_void (rval, ICV_CAST, complain));
+    finish_expr_stmt (rval);
 }
 
 /* This function is responsible for initializing EXP with INIT
@@ -1708,36 +1720,18 @@ constant_value_1 (tree decl, bool integral_p)
 {
   while (TREE_CODE (decl) == CONST_DECL
 	 || (integral_p
-	     ? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+	     ? decl_constant_var_p (decl)
 	     : (TREE_CODE (decl) == VAR_DECL
 		&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
     {
       tree init;
-      /* Static data members in template classes may have
-	 non-dependent initializers.  References to such non-static
-	 data members are not value-dependent, so we must retrieve the
-	 initializer here.  The DECL_INITIAL will have the right type,
-	 but will not have been folded because that would prevent us
-	 from performing all appropriate semantic checks at
-	 instantiation time.  */
-      if (DECL_CLASS_SCOPE_P (decl)
-	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
-	  && uses_template_parms (CLASSTYPE_TI_ARGS
-				  (DECL_CONTEXT (decl))))
-	{
-	  ++processing_template_decl;
-	  init = fold_non_dependent_expr (DECL_INITIAL (decl));
-	  --processing_template_decl;
-	}
-      else
-	{
-	  /* If DECL is a static data member in a template
-	     specialization, we must instantiate it here.  The
-	     initializer for the static data member is not processed
-	     until needed; we need it now.  */
-	  mark_used (decl);
-	  init = DECL_INITIAL (decl);
-	}
+      /* If DECL is a static data member in a template
+	 specialization, we must instantiate it here.  The
+	 initializer for the static data member is not processed
+	 until needed; we need it now.  */
+      mark_used (decl);
+      mark_rvalue_use (decl);
+      init = DECL_INITIAL (decl);
       if (init == error_mark_node)
 	{
 	  if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
@@ -1758,8 +1752,9 @@ constant_value_1 (tree decl, bool integral_p)
 	init = TREE_VALUE (init);
       if (!init
 	  || !TREE_TYPE (init)
+	  || uses_template_parms (init)
 	  || (integral_p
-	      ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
+	      ? false
 	      : (!TREE_CONSTANT (init)
 		 /* Do not return an aggregate constant (of which
 		    string literals are a special case), as we do not
@@ -2302,7 +2297,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
 	      tree arraytype, domain;
 	      vecinit = VEC_index (tree, *init, 0);
 	      if (TREE_CONSTANT (nelts))
-		domain = compute_array_index_type (NULL_TREE, nelts);
+		domain = compute_array_index_type (NULL_TREE, nelts, complain);
 	      else
 		{
 		  domain = NULL_TREE;
@@ -2878,6 +2873,8 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree try_block = NULL_TREE;
   int num_initialized_elts = 0;
   bool is_global;
+  tree const_init = NULL_TREE;
+  tree obase = base;
   bool xvalue = false;
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
@@ -2986,26 +2983,75 @@ build_vec_init (tree base, tree maxindex, tree init,
       try_block = begin_try_block ();
     }
 
+  /* Maybe pull out constant value when from_array? */
+
   if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
     {
       /* Do non-default initialization of non-trivial arrays resulting from
 	 brace-enclosed initializers.  */
       unsigned HOST_WIDE_INT idx;
-      tree elt;
+      tree field, elt;
+      /* Should we try to create a constant initializer?  */
+      bool try_const = (literal_type_p (inner_elt_type)
+			|| TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type));
+      bool saw_non_const = false;
+      bool saw_const = false;
+      /* If we're initializing a static array, we want to do static
+	 initialization of any elements with constant initializers even if
+	 some are non-constant.  */
+      bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
+      VEC(constructor_elt,gc) *new_vec;
       from_array = 0;
 
-      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
+      if (try_const)
+	new_vec = VEC_alloc (constructor_elt, gc, CONSTRUCTOR_NELTS (init));
+      else
+	new_vec = NULL;
+
+      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt)
 	{
 	  tree baseref = build1 (INDIRECT_REF, type, base);
+	  tree one_init;
 
 	  num_initialized_elts++;
 
 	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
 	  if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
-	    finish_expr_stmt (build_aggr_init (baseref, elt, 0, complain));
+	    one_init = build_aggr_init (baseref, elt, 0, complain);
 	  else
-	    finish_expr_stmt (cp_build_modify_expr (baseref, NOP_EXPR,
-                                                    elt, complain));
+	    one_init = cp_build_modify_expr (baseref, NOP_EXPR,
+					     elt, complain);
+
+	  if (try_const)
+	    {
+	      tree e = one_init;
+	      if (TREE_CODE (e) == EXPR_STMT)
+		e = TREE_OPERAND (e, 0);
+	      if (TREE_CODE (e) == CONVERT_EXPR
+		  && VOID_TYPE_P (TREE_TYPE (e)))
+		e = TREE_OPERAND (e, 0);
+	      e = maybe_constant_init (e);
+	      if (reduced_constant_expression_p (e))
+		{
+		  CONSTRUCTOR_APPEND_ELT (new_vec, field, e);
+		  if (do_static_init)
+		    one_init = NULL_TREE;
+		  else
+		    one_init = build2 (INIT_EXPR, type, baseref, e);
+		  saw_const = true;
+		}
+	      else
+		{
+		  if (do_static_init)
+		    CONSTRUCTOR_APPEND_ELT (new_vec, field,
+					    build_zero_init (TREE_TYPE (e),
+							     NULL_TREE, true));
+		  saw_non_const = true;
+		}
+	    }
+
+	  if (one_init)
+	    finish_expr_stmt (one_init);
 	  current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
 	  finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
@@ -3014,6 +3060,16 @@ build_vec_init (tree base, tree maxindex, tree init,
                                                complain));
 	}
 
+      if (try_const)
+	{
+	  if (!saw_non_const)
+	    const_init = build_constructor (atype, new_vec);
+	  else if (do_static_init && saw_const)
+	    DECL_INITIAL (obase) = build_constructor (atype, new_vec);
+	  else
+	    VEC_free (constructor_elt, gc, new_vec);
+	}
+
       /* Clear out INIT so that we don't get confused below.  */
       init = NULL_TREE;
     }
@@ -3161,6 +3217,9 @@ build_vec_init (tree base, tree maxindex, tree init,
     }
 
   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
+
+  if (const_init)
+    return build2 (INIT_EXPR, atype, obase, const_init);
   return stmt_expr;
 }
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 33d8561..9027760 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7176,7 +7176,8 @@ cp_parser_constant_expression (cp_parser* parser,
   saved_non_integral_constant_expression_p = parser->non_integral_constant_expression_p;
   /* We are now parsing a constant-expression.  */
   parser->integral_constant_expression_p = true;
-  parser->allow_non_integral_constant_expression_p = allow_non_constant_p;
+  parser->allow_non_integral_constant_expression_p
+    = (allow_non_constant_p || cxx_dialect >= cxx0x);
   parser->non_integral_constant_expression_p = false;
   /* Although the grammar says "conditional-expression", we parse an
      "assignment-expression", which also permits "throw-expression"
@@ -7195,7 +7196,8 @@ cp_parser_constant_expression (cp_parser* parser,
     = saved_allow_non_integral_constant_expression_p;
   if (allow_non_constant_p)
     *non_constant_p = parser->non_integral_constant_expression_p;
-  else if (parser->non_integral_constant_expression_p)
+  else if (parser->non_integral_constant_expression_p
+	   && cxx_dialect < cxx0x)
     expression = error_mark_node;
   parser->non_integral_constant_expression_p
     = saved_non_integral_constant_expression_p;
@@ -14975,8 +14977,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 		= cp_parser_constant_expression (parser,
 						 /*allow_non_constant=*/true,
 						 &non_constant_p);
-	      if (!non_constant_p)
-		bounds = fold_non_dependent_expr (bounds);
+	      if (!non_constant_p || cxx_dialect >= cxx0x)
+		/* OK */;
 	      /* Normally, the array bound must be an integral constant
 		 expression.  However, as an extension, we allow VLAs
 		 in function scopes as long as they aren't part of a
@@ -16408,7 +16410,15 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
 					/*allow_non_constant_p=*/true,
 					non_constant_p);
       if (!*non_constant_p)
-	initializer = fold_non_dependent_expr (initializer);
+	{
+	  /* We only want to fold if this is really a constant
+	     expression.  FIXME Actually, we don't want to fold here, but in
+	     cp_finish_decl.  */
+	  tree folded = fold_non_dependent_expr (initializer);
+	  folded = maybe_constant_value (folded);
+	  if (TREE_CONSTANT (folded))
+	    initializer = folded;
+	}
     }
   else
     initializer = cp_parser_braced_list (parser, non_constant_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9a72ea8..d3c1c1c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4845,29 +4845,6 @@ fold_non_dependent_expr (tree expr)
   return fold_non_dependent_expr_sfinae (expr, tf_error);
 }
 
-/* EXPR is an expression which is used in a constant-expression context.
-   For instance, it could be a VAR_DECL with a constant initializer.
-   Extract the innermost constant expression.
-
-   This is basically a more powerful version of
-   integral_constant_value, which can be used also in templates where
-   initializers can maintain a syntactic rather than semantic form
-   (even if they are non-dependent, for access-checking purposes).  */
-
-static tree
-fold_decl_constant_value (tree expr)
-{
-  tree const_expr = expr;
-  do
-    {
-      expr = fold_non_dependent_expr (const_expr);
-      const_expr = integral_constant_value (expr);
-    }
-  while (expr != const_expr);
-
-  return expr;
-}
-
 /* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
    must be a function or a pointer-to-function type, as specified
    in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
@@ -5069,23 +5046,23 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
     {
       tree t = build_integral_nontype_arg_conv (type, expr, complain);
-      t = fold_decl_constant_value (t);
+      t = maybe_constant_value (t);
       if (t != error_mark_node)
 	expr = t;
 
       if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (expr)))
 	return error_mark_node;
 
-      /* Conversion was allowed: fold it to a bare integer constant.  */
-      expr = fold (expr);
-
       /* Notice that there are constant expressions like '4 % 0' which
 	 do not fold into integer constants.  */
       if (TREE_CODE (expr) != INTEGER_CST)
 	{
 	  if (complain & tf_error)
-	    error ("%qE is not a valid template argument for type %qT "
-		   "because it is a non-constant expression", expr, type);
+	    {
+	      error ("%qE is not a valid template argument for type %qT "
+		     "because it is a non-constant expression", expr, type);
+	      cxx_constant_value (expr);
+	    }
 	  return NULL_TREE;
 	}
     }
@@ -9637,8 +9614,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 		RETURN (error_mark_node);
 	      }
 	    type = complete_type (type);
-	    DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
-	      = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t);
+	    /* Wait until cp_finish_decl to set this again, to handle
+	       circular dependency (template/instantiate6.C). */
+	    DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) = 0;
 	    type = check_var_type (DECL_NAME (r), type);
 
 	    if (DECL_HAS_VALUE_EXPR_P (t))
@@ -10125,9 +10103,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    && !TREE_TYPE (max))
 	  TREE_TYPE (max) = TREE_TYPE (TREE_OPERAND (max, 0));
 
-	max = mark_rvalue_use (max);
-	max = fold_decl_constant_value (max);
-
 	/* If we're in a partial instantiation, preserve the magic NOP_EXPR
 	   with TREE_SIDE_EFFECTS that indicates this is not an integral
 	   constant expression.  */
@@ -10138,38 +10113,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    TREE_SIDE_EFFECTS (max) = 1;
 	  }
 
-	if (TREE_CODE (max) != INTEGER_CST
-	    && !at_function_scope_p ()
-	    && !TREE_SIDE_EFFECTS (max)
-	    && !value_dependent_expression_p (max))
-	  {
-	    if (complain & tf_error)
-	      error ("array bound is not an integer constant");
-	    return error_mark_node;
-	  }
-
-	/* [temp.deduct]
-
-	   Type deduction may fail for any of the following
-	   reasons:
-
-	     Attempting to create an array with a size that is
-	     zero or negative.  */
-	if (integer_zerop (max) && !(complain & tf_error))
-	  /* We must fail if performing argument deduction (as
-	     indicated by the state of complain), so that
-	     another substitution can be found.  */
-	  return error_mark_node;
-	else if (TREE_CODE (max) == INTEGER_CST
-		 && INT_CST_LT (max, integer_zero_node))
-	  {
-	    if (complain & tf_error)
-	      error ("creating array with negative size (%qE)", max);
-
-	    return error_mark_node;
-	  }
-
-	return compute_array_index_type (NULL_TREE, max);
+	return compute_array_index_type (NULL_TREE, max, complain);
       }
 
     case TEMPLATE_TYPE_PARM:
@@ -11658,10 +11602,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 
     case DECL_EXPR:
       {
-	tree decl;
+	tree decl, pattern_decl;
 	tree init;
 
-	decl = DECL_EXPR_DECL (t);
+	pattern_decl = decl = DECL_EXPR_DECL (t);
 	if (TREE_CODE (decl) == LABEL_DECL)
 	  finish_label_decl (DECL_NAME (decl));
 	else if (TREE_CODE (decl) == USING_DECL)
@@ -11698,6 +11642,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 		  finish_anon_union (decl);
 		else
 		  {
+		    int const_init = false;
 		    maybe_push_decl (decl);
 		    if (TREE_CODE (decl) == VAR_DECL
 			&& DECL_PRETTY_FUNCTION_P (decl))
@@ -11730,7 +11675,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 			  init = t;
 		      }
 
-		    cp_finish_decl (decl, init, false, NULL_TREE, 0);
+		    if (TREE_CODE (decl) == VAR_DECL)
+		      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
+				    (pattern_decl));
+		    cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
 		  }
 	      }
 	  }
@@ -16894,6 +16842,7 @@ instantiate_decl (tree d, int defer_ok,
 	{
 	  tree ns;
 	  tree init;
+	  bool const_init = false;
 
 	  ns = decl_namespace_context (d);
 	  push_nested_namespace (ns);
@@ -16902,7 +16851,11 @@ instantiate_decl (tree d, int defer_ok,
 			      args,
 			      tf_warning_or_error, NULL_TREE,
 			      /*integral_constant_expression_p=*/false);
-	  cp_finish_decl (d, init, /*init_const_expr_p=*/false,
+	  /* Make sure the initializer is still constant, in case of
+	     circular dependency (template/instantiate6.C). */
+	  const_init
+	    = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
+	  cp_finish_decl (d, init, /*init_const_expr_p=*/const_init,
 			  /*asmspec_tree=*/NULL_TREE,
 			  LOOKUP_ONLYCONVERTING);
 	  pop_nested_class ();
@@ -16973,6 +16926,7 @@ instantiate_decl (tree d, int defer_ok,
   if (TREE_CODE (d) == VAR_DECL)
     {
       tree init;
+      bool const_init = false;
 
       /* Clear out DECL_RTL; whatever was there before may not be right
 	 since we've reset the type of the declaration.  */
@@ -16980,7 +16934,8 @@ instantiate_decl (tree d, int defer_ok,
       DECL_IN_AGGR_P (d) = 0;
 
       /* The initializer is placed in DECL_INITIAL by
-	 regenerate_decl_from_template.  Pull it out so that
+	 regenerate_decl_from_template so we don't need to
+	 push/pop_access_scope again here.  Pull it out so that
 	 cp_finish_decl can process it.  */
       init = DECL_INITIAL (d);
       DECL_INITIAL (d) = NULL_TREE;
@@ -16993,7 +16948,8 @@ instantiate_decl (tree d, int defer_ok,
 
       /* Enter the scope of D so that access-checking works correctly.  */
       push_nested_class (DECL_CONTEXT (d));
-      cp_finish_decl (d, init, false, NULL_TREE, 0);
+      const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
+      cp_finish_decl (d, init, const_init, NULL_TREE, 0);
       pop_nested_class ();
     }
   else if (TREE_CODE (d) == FUNCTION_DECL)
@@ -17633,6 +17589,23 @@ dependent_scope_p (tree scope)
    [temp.dep.constexpr].  EXPRESSION is already known to be a constant
    expression.  */
 
+/* FIXME this predicate is not appropriate for general expressions; the
+   predicates we want instead are "valid constant expression, value
+   dependent or not?", "really constant expression, not value dependent?"
+   and "instantiation-dependent?".  Try to integrate with
+   potential_constant_expression?
+
+   fold_non_dependent_expr: fold if constant and not type-dependent and not value-dependent.
+     (what about instantiation-dependent constant-expressions?)
+   is_late_template_attribute: defer if instantiation-dependent.
+   compute_array_index_type: proceed if constant and not t- or v-dependent
+     if instantiation-dependent, need to remember full expression
+   uses_template_parms: FIXME - need to audit callers
+   tsubst_decl [function_decl]: Why is this using value_dependent_expression_p?
+   dependent_type_p [array_type]: dependent if index type is dependent
+     (or non-constant?)
+   static_assert - instantiation-dependent */
+
 bool
 value_dependent_expression_p (tree expression)
 {
@@ -17689,7 +17662,8 @@ value_dependent_expression_p (tree expression)
 	    /* If there are no operands, it must be an expression such
 	       as "int()". This should not happen for aggregate types
 	       because it would form non-constant expressions.  */
-	    gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+	    gcc_assert (cxx_dialect >= cxx0x
+			|| INTEGRAL_OR_ENUMERATION_TYPE_P (type));
 
 	    return false;
 	  }
@@ -17733,12 +17707,6 @@ value_dependent_expression_p (tree expression)
       return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
 	      || value_dependent_expression_p (TREE_OPERAND (expression, 1)));
 
-    case CALL_EXPR:
-      /* A CALL_EXPR may appear in a constant expression if it is a
-	 call to a builtin function, e.g., __builtin_constant_p.  All
-	 such calls are value-dependent.  */
-      return true;
-
     case NONTYPE_ARGUMENT_PACK:
       /* A NONTYPE_ARGUMENT_PACK is value-dependent if any packed argument
          is value-dependent.  */
@@ -17771,6 +17739,30 @@ value_dependent_expression_p (tree expression)
 		|| has_value_dependent_address (op));
       }
 
+    case CALL_EXPR:
+      {
+	tree fn = get_callee_fndecl (expression);
+	int i, nargs;
+	if (!fn && value_dependent_expression_p (CALL_EXPR_FN (expression)))
+	  return true;
+	nargs = call_expr_nargs (expression);
+	for (i = 0; i < nargs; ++i)
+	  {
+	    tree op = CALL_EXPR_ARG (expression, i);
+	    /* In a call to a constexpr member function, look through the
+	       implicit ADDR_EXPR on the object argument so that it doesn't
+	       cause the call to be considered value-dependent.  We also
+	       look through it in potential_constant_expression.  */
+	    if (i == 0 && fn && DECL_DECLARED_CONSTEXPR_P (fn)
+		&& DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+		&& TREE_CODE (op) == ADDR_EXPR)
+	      op = TREE_OPERAND (op, 0);
+	    if (value_dependent_expression_p (op))
+	      return true;
+	  }
+	return false;
+      }
+
     default:
       /* A constant expression is value-dependent if any subexpression is
 	 value-dependent.  */
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index da56d4d..709e44c 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -328,6 +328,8 @@ build_typeid (tree exp)
   if (processing_template_decl)
     return build_min (TYPEID_EXPR, const_type_info_type_node, exp);
 
+  /* FIXME when integrating with c_fully_fold, mark
+     resolves_to_fixed_type_p case as a non-constant expression.  */
   if (TREE_CODE (exp) == INDIRECT_REF
       && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
       && TYPE_POLYMORPHIC_P (TREE_TYPE (exp))
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 039f0a5..397d383 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4618,6 +4618,7 @@ finish_static_assert (tree condition, tree message, location_t location,
   /* Fold the expression and convert it to a boolean value. */
   condition = fold_non_dependent_expr (condition);
   condition = cp_convert (boolean_type_node, condition);
+  condition = maybe_constant_value (condition);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
@@ -4632,7 +4633,10 @@ finish_static_assert (tree condition, tree message, location_t location,
         /* Report the error. */
         error ("static assertion failed: %E", message);
       else if (condition && condition != error_mark_node)
-        error ("non-constant condition for static assertion");
+	{
+	  error ("non-constant condition for static assertion");
+	  cxx_constant_value (condition);
+	}
       input_location = saved_loc;
     }
 }
@@ -5273,7 +5277,9 @@ ensure_literal_type_for_constexpr_object (tree decl)
 {
   tree type = TREE_TYPE (decl);
   if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
-      && !processing_template_decl && !literal_type_p (type))
+      && !processing_template_decl
+      /* The call to complete_type is just for initializer_list.  */
+      && !literal_type_p (complete_type (type)))
     {
       error ("the type %qT of constexpr variable %qD is not literal",
              type, decl);
@@ -6837,6 +6843,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
     return r;
 }
 
+/* Returns true if T is a valid subexpression of a constant expression,
+   even if it isn't itself a constant expression.  */
+
+bool
+is_sub_constant_expr (tree t)
+{
+  bool non_constant_p = false;
+  cxx_eval_constant_expression (NULL, t, true, false, &non_constant_p);
+  return !non_constant_p;
+}
+
 /* If T represents a constant expression returns its reduced value.
    Otherwise return error_mark_node.  If T is dependent, then
    return NULL.  */
@@ -7257,7 +7274,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      if (integer_zerop (decl_constant_value (TREE_OPERAND (t, 1))))
+      if (integer_zerop (maybe_constant_value (TREE_OPERAND (t, 1))))
 	return false;
       else
 	goto binary;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 511730a..e55b5bc 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3235,6 +3235,7 @@ bool
 cast_valid_in_integral_constant_expression_p (tree type)
 {
   return (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+	  || cxx_dialect >= cxx0x
 	  || dependent_type_p (type)
 	  || type == error_mark_node);
 }
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 967fe4d..0da3278 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1930,6 +1930,9 @@ decay_conversion (tree exp)
       return error_mark_node;
     }
 
+  /* FIXME remove? at least need to remember that this isn't really a
+     constant expression if EXP isn't decl_constant_var_p, like with
+     C_MAYBE_CONST_EXPR.  */
   exp = decl_constant_value (exp);
   if (error_operand_p (exp))
     return error_mark_node;
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b9c027a..f1bd16e 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -714,9 +714,6 @@ store_init_value (tree decl, tree init, int flags)
 
   if (MAYBE_CLASS_TYPE_P (type))
     {
-      gcc_assert (!type_has_nontrivial_copy_init (type)
-		  || TREE_CODE (init) == CONSTRUCTOR);
-
       if (TREE_CODE (init) == TREE_LIST)
 	{
 	  error ("constructor syntax used, but no constructor declared "
@@ -743,8 +740,32 @@ store_init_value (tree decl, tree init, int flags)
 
   /* End of special C++ code.  */
 
-  /* Digest the specified initializer into an expression.  */
-  value = digest_init_flags (type, init, flags);
+  if (flags & LOOKUP_ALREADY_DIGESTED)
+    value = init;
+  else
+    /* Digest the specified initializer into an expression.  */
+    value = digest_init_flags (type, init, flags);
+
+  /* In C++0x constant expression is a semantic, not syntactic, property.
+     In C++98, make sure that what we thought was a constant expression at
+     template definition time is still constant.  */
+  if ((cxx_dialect >= cxx0x
+       || DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+      && (decl_maybe_constant_var_p (decl)
+	  || TREE_STATIC (decl)))
+    {
+      bool const_init;
+      value = fold_non_dependent_expr (value);
+      value = maybe_constant_init (value);
+      if (DECL_DECLARED_CONSTEXPR_P (decl))
+	/* Diagnose a non-constant initializer for constexpr.  */
+	value = cxx_constant_value (value);
+      const_init = (reduced_constant_expression_p (value)
+		    || error_operand_p (value));
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
+      TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
+    }
+
   /* If the initializer is not a constant, fill in DECL_INITIAL with
      the bits that are constant, and then return an expression that
      will perform the dynamic initialization.  */
@@ -769,8 +790,7 @@ check_narrowing (tree type, tree init)
   bool ok = true;
   REAL_VALUE_TYPE d;
 
-  if (DECL_P (init))
-    init = decl_constant_value (init);
+  init = maybe_constant_value (init);
 
   if (TREE_CODE (type) == INTEGER_TYPE
       && TREE_CODE (ftype) == REAL_TYPE)
@@ -1632,7 +1652,11 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
       && !TYPE_HAS_USER_CONSTRUCTOR (type))
     {
       exp = build_value_init (type, complain);
-      return get_target_expr (exp);
+      exp = get_target_expr (exp);
+      /* FIXME this is wrong */
+      if (literal_type_p (type))
+	TREE_CONSTANT (exp) = true;
+      return exp;
     }
 
   /* Call the constructor.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr.C
new file mode 100644
index 0000000..36939e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr.C
@@ -0,0 +1,15 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+constexpr T do_get(T* x, int n) {
+  return x[n - 1];
+}
+
+template<class T, int N>
+constexpr T get(T (&x)[N]) {
+  return do_get(x, N);
+}
+
+constexpr int arr_i[] = {1};
+constexpr auto var = get(arr_i); // #2
+static_assert(var == arr_i[0], "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr2.C
new file mode 100644
index 0000000..7cf7334
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr2.C
@@ -0,0 +1,21 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+struct IsNegative {
+  int dummy; // Workaround for empty class problem
+  constexpr IsNegative() : dummy(0) {}
+  constexpr bool operator()(const T& x) {
+    return x < T(0);
+  }
+};
+
+template<class T, int N, class Pred>
+constexpr bool has_neg(T (&x)[N], Pred p) {
+  return p(x[0]) || p(x[1]);
+}
+
+constexpr int a[] = {1, -2};
+
+constexpr auto answer = has_neg(a, IsNegative<int>{}); // #1
+
+static_assert(answer, "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr3.C
new file mode 100644
index 0000000..f84cb52
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr3.C
@@ -0,0 +1,19 @@
+// { dg-options -std=c++0x }
+
+constexpr bool is_negative(int x) {
+  return x < 0;
+};
+
+constexpr bool do_has_neg(const int* x, bool(*p)(int)) {
+ return p(x[0]) || p(x[1]);  // Line 6
+}
+
+constexpr bool has_neg(const int (&x)[2], bool(*p)(int)) {
+ return do_has_neg(x, p); // Line 10
+}
+
+constexpr int a[] = {1, -2};
+
+constexpr auto answer = has_neg(a, is_negative); // Line 15
+
+static_assert(answer, "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr4.C
new file mode 100644
index 0000000..697d2d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr4.C
@@ -0,0 +1,23 @@
+// { dg-options -std=c++0x }
+
+constexpr const int do_last(const int* x, int n) {
+ return x[n - 1];
+}
+
+struct IsNegative {
+  constexpr bool operator()(const int& x) {
+    return x < 0;
+  }
+};
+
+template<int N, class Pred>
+constexpr bool has_neg(const int (&x)[N], Pred p) {
+  return p(do_last(x, N)); // Line 13
+}
+
+constexpr int a[] = {1, -2};
+
+constexpr auto answer = has_neg(a, IsNegative{}); // Line 18
+
+static_assert(answer, "Error");
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr5.C
new file mode 100644
index 0000000..d58f254
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr5.C
@@ -0,0 +1,32 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+constexpr T do_last(T* x, int n) {
+ return x[n - 1]; //
+}
+
+template<class T, int N>
+constexpr T last(T (&x)[N]) {
+ return do_last(x, N);
+}
+
+constexpr bool is_negative(int x) { return x < 0; }
+
+template<class T>
+struct IsNegative {
+  constexpr bool operator()(const T& x) {
+    return x < T(0);
+  }
+};
+
+template<class T, int N, class Pred>
+constexpr bool has_neg(T (&x)[N], Pred p) {
+  return p(last(x)); // Line 22
+}
+
+constexpr int a[] = {1, -2};
+
+constexpr auto answer1 = has_neg(a, IsNegative<int>{}); // Line 27
+constexpr auto answer2 = has_neg(a, is_negative);
+
+static_assert(answer2 == answer1, "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C
new file mode 100644
index 0000000..17dd6e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C
@@ -0,0 +1,18 @@
+// { dg-options "-std=c++0x" }
+
+typedef decltype(sizeof(char)) size_type;
+
+template<class T, size_type N>
+constexpr size_type size(T (&)[N]) { return N; }
+
+double array_double[] = { 1.0, 2.0, 3.0 };
+
+constexpr auto sz_d = size(array_double);
+
+static_assert(sz_d == 3, "Array size failure");
+
+void f(bool (&param)[2]) {
+  static_assert(size(param) == 2, "Array size failure"); // Line 13
+  short data[] = {-1, 2, -45, 6, 88, 99, -345};
+  static_assert(size(data) == 7, "Array size failure");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array.C
new file mode 100644
index 0000000..e37400a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array.C
@@ -0,0 +1,15 @@
+// { dg-options -std=c++0x }
+// { dg-final { scan-assembler-not "static_initialization" } }
+
+struct A
+{
+  int i;
+  constexpr A(): i(0) { }
+};
+
+struct B
+{
+  A a[4];
+};
+
+extern const B b{};
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-base.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-base.C
new file mode 100644
index 0000000..774df31
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-base.C
@@ -0,0 +1,17 @@
+// Test base/member class and static_assert with constexpr
+// { dg-options -std=c++0x }
+
+struct A {
+  int i;
+  constexpr A(int _i): i(_i) { }
+};
+struct B: A {
+  A a;
+  int j;
+  constexpr B(int _ib, int _ia, int _j): A(_ib), a(_ia), j(_j) { }
+};
+
+constexpr B b (12, 24, 36);
+
+#define SA(X) static_assert (X, #X)
+SA(b.i==12 && b.a.i==24 && b.j==36);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-complex.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-complex.C
new file mode 100644
index 0000000..fbaae5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-complex.C
@@ -0,0 +1,17 @@
+// Make sure C99 complex works with constexpr
+// { dg-options -std=c++0x }
+
+struct complex
+{
+  typedef float value_type;
+  typedef __complex__ float _ComplexT;
+
+  constexpr complex(_ComplexT __z) : _M_value(__z) { }
+
+  constexpr complex(float __r = 0.0f, float __i = 0.0f)
+  : _M_value(__r + __i * 1.0fi) { }
+
+private:
+  _ComplexT _M_value;
+};
+constexpr complex c1;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C
new file mode 100644
index 0000000..7d7a33d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C
@@ -0,0 +1,43 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 1
+struct A2
+{
+  static const int eights = 888;
+  static constexpr int nines = 999;
+};
+
+A2 a;
+
+// 2
+struct pixel
+{
+  int x, y;
+};
+constexpr pixel ur = { 1294, 1024 }; // OK
+
+// p4
+struct Length
+{
+   explicit constexpr Length(int i = 0) : val(i) { }
+private:
+   int val;
+};
+
+constexpr int myabs(int x)
+{ return x < 0 ? -x : x; }    // OK
+
+Length l(myabs(-97)); // OK
+
+// p6
+class debug_flag
+{
+public:
+   explicit debug_flag(bool);
+   constexpr bool is_on(); // { dg-error "enclosing class .* not a literal type" }
+private:
+   bool flag;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
new file mode 100644
index 0000000..4d4ce78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -0,0 +1,48 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename _Tp, _Tp v>
+  struct A3
+  {
+    typedef _Tp value_type;
+    typedef A3<value_type,v> type;
+
+    static constexpr value_type value = v;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Partial specialization.
+template<typename _Tp, _Tp v>
+  struct A3<_Tp*, v>
+  {
+    typedef _Tp* value_type;
+    typedef A3<value_type,v> type;
+
+    static constexpr value_type value = v;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Explicit specialization.
+template<>
+  struct A3<unsigned short, 0>
+  {
+    typedef unsigned short value_type;
+    typedef A3<value_type, 0> type;
+
+    static constexpr value_type value = 0;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Explicitly instantiate.
+template struct A3<int, 415>;
+
+// Extern explicitly instantiate.
+extern template struct A3<int, 510>;
+
+// Use.
+A3<int, 1111> a31;
+// FIXME should this be an error?
+A3<char, 9999> a32;		// { dg-warning "overflow" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-deref.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-deref.C
new file mode 100644
index 0000000..7363e98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-deref.C
@@ -0,0 +1,16 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  const int *p[2];
+};
+
+constexpr const int * f(const int *p) { return p; }
+
+int main()
+{
+  constexpr int i = 42;
+  constexpr int j = *&i;	   // OK
+  constexpr int k = *A{{&i}}.p[0]; // OK
+  constexpr int l = *f(&i);	   // OK
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
new file mode 100644
index 0000000..a3706d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
@@ -0,0 +1,21 @@
+// Test that we explain why a template instantiation isn't constexpr
+// { dg-options -std=c++0x }
+// { dg-prune-output "not a constexpr function" }
+
+template <class T>
+struct A
+{
+  T t;
+  constexpr int f() { return 42; }
+};
+
+struct B { B(); operator int(); };
+
+constexpr A<int> ai = { 42 };
+constexpr int i = ai.f();
+
+constexpr int b = A<B>().f();	// { dg-error "enclosing class" }
+
+template <class T>
+constexpr int f (T t) { return 42; }
+constexpr int x = f(B());	// { dg-error "parameter" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-eh-spec.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-eh-spec.C
new file mode 100644
index 0000000..6d231fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-eh-spec.C
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+template<class T> class my_limits {
+public:
+  static constexpr T min() throw() { return T(); }
+  static constexpr T max() noexcept { return T(); }
+};
+
+constexpr double var_min = my_limits<double>::min(); // #1  OK
+constexpr double var_max = my_limits<double>::max(); // #2 Error
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis.C
new file mode 100644
index 0000000..5d090b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis.C
@@ -0,0 +1,5 @@
+// { dg-options -std=c++0x }
+constexpr int ellipsis(...) { return 1; }
+
+constexpr int ellipsis_c = ellipsis(); // OK
+constexpr int ellipsis_c2 = ellipsis(42); // Internal error
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C
new file mode 100644
index 0000000..0bb6904
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ellipsis2.C
@@ -0,0 +1,12 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  A();
+  A(const A&);
+  bool empty();
+};
+
+constexpr int ellipsis(...) { return 1; }
+
+static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition|empty" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty.C
new file mode 100644
index 0000000..a9fc438
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct Empty {};
+
+constexpr bool f(Empty) { return true; }
+
+constexpr bool x(f(Empty{}));
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty2.C
new file mode 100644
index 0000000..ef21211
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty2.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct IsLiteral {};
+
+constexpr IsLiteral bar(IsLiteral x) { return x; }
+
+constexpr auto xy = bar(IsLiteral()); // #1  Error, but should be OK
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty3.C
new file mode 100644
index 0000000..e0026fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty3.C
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+
+struct IsLiteral {};
+
+constexpr auto ab = IsLiteral();
+
+constexpr IsLiteral bar(IsLiteral x) { return x; }
+
+constexpr auto xy = bar(ab);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty4.C
new file mode 100644
index 0000000..b07f924
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty4.C
@@ -0,0 +1,34 @@
+// { dg-options -std=c++0x }
+
+typedef decltype(sizeof(char)) size_type;
+
+template<class T, size_type N, class Pred>
+constexpr size_type do_find_if_or_stop(T (&x)[N], size_type i, Pred p);
+
+template<class T, size_type N, class Pred>
+constexpr size_type do_find_if(T (&x)[N], size_type i, Pred p) {
+  return p(x[i]) ? i : do_find_if_or_stop(x, i + 1, p);  // line 8
+}
+
+template<class T, size_type N, class Pred>
+constexpr size_type do_find_if_or_stop(T (&x)[N], size_type i, Pred p) {
+  return i == N ? N : do_find_if(x, i, p);
+} // Line 14
+
+template<class T, size_type N, class Pred>
+constexpr size_type find_if(T (&x)[N], Pred p) {
+	return do_find_if(x, 0, p); // Line 18
+}
+
+constexpr long items_long[] = {1, 2, 3, 4, -5, 6, -7, 8};
+
+template<class T>
+struct IsNegative {
+	constexpr bool operator()(const T& x) {
+		return x < T(0);
+	}
+};
+
+constexpr auto pos1 = find_if(items_long, IsNegative<long>{}); // Line 30
+
+static_assert(pos1 == 4, "find_if failure");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty5.C
new file mode 100644
index 0000000..9bd9aa5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty5.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct A { };
+struct B: A { };
+
+constexpr B b { };
+constexpr A a = b;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
new file mode 100644
index 0000000..f2b5384
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
@@ -0,0 +1,94 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.1 constant-expression functions
+// 1 examples
+
+
+
+
+
+// 2 defined before first use
+// NOTE: this is only needed in contexts that require a constant-expression
+struct S {
+    constexpr int twice();
+    constexpr int t();		// { dg-message "used but never defined" }
+private:
+    static constexpr int val;  // constexpr variable
+};
+constexpr int S::val = 7;
+constexpr int S::twice() { return val + val; }
+constexpr S s = { };
+int x1 = s.twice();     // ok
+int x2 = s.t();         // error: S::t() not defined
+constexpr int x2a = s.t();     // { dg-error "S::t" } error: S::t() not defined
+constexpr int ff();     // ok
+constexpr int gg();     // ok
+int x3 = ff();          // error: ff() not defined
+constexpr int x3a = ff();      // { dg-error "ff" } error: ff() not defined
+constexpr int ff() { return 1; }        // too late
+constexpr int gg() { return 2; }
+int x4 = gg();  // ok
+
+
+// 4.2 const-expression data
+
+// 2
+// storage  not allocated untill address taken
+constexpr double x = 9484.748;
+const double* p = &x;          // the &x forces x into memory
+
+// 4.3 constant-expression constructors
+
+// 1
+struct complex {
+   constexpr complex(double r, double i) : re(r), im(i) { }
+   constexpr double real() { return re; }
+   constexpr double imag() { return im; }
+private:
+   double re;
+   double im;
+};
+constexpr complex I(0, 1);  // OK -- literal complex
+
+
+// 2 invoked with non-const args
+double x5 = 1.0;
+constexpr complex unit(x5, 0);	// { dg-error "x5|argument" } error: x5 non-constant
+const complex one(x5, 0);   // OK, ‘‘ordinary const’’ -- dynamic
+                           //   initialization
+constexpr double xx = I.real(); // OK
+complex z(2, 4);           // OK -- ordinary variable
+
+// 3
+constexpr complex v[] = {
+     complex(0, 0), complex(1, 1), complex(2, 2)
+};
+constexpr double x6 = v[2].real(); // OK
+
+// 4 
+  constexpr int i = 98;
+  typedef __INTPTR_TYPE__ intptr_t;
+  constexpr intptr_t ip = (intptr_t) &i;	// { dg-error "constant" }
+
+// 4.3.2 copy-constructor
+constexpr complex operator+(complex z, complex w)
+{
+  return complex(z.real() + w.real(), z.imag() + w.imag()); // fine
+}
+constexpr complex I2 = I + I;                 // OK
+struct resource {
+  int id;
+  constexpr resource(int i) : id(i) { }       // fine
+  resource(const resource& r) : id(r.id)      // oops, not constexpr
+  {
+    //cout << id << " copied" << endl;
+  }
+};
+constexpr resource f(resource d)
+{ return d; }                  // { dg-error "not .constexpr" }
+constexpr resource d = f(9);   // { dg-error "resource" }
+
+// 4.4 floating-point constant expressions
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
new file mode 100644
index 0000000..5896c20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -0,0 +1,23 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.5.3 constant expressions
+
+// p 4
+struct A {
+  constexpr A(int i) : val(i) { }
+  constexpr operator int() { return val; }
+  constexpr operator long() { return -1; }
+private:
+  int val;
+};
+
+template<int I> struct X { static const int i = I; };
+constexpr A a = 42;
+
+X<a> x;	    // OK: unique conversion to int
+int ar[X<a>::i]; // also OK
+int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous conversion
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C
new file mode 100644
index 0000000..597603c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex3.C
@@ -0,0 +1,30 @@
+// { dg-options "-std=c++0x" }
+
+#define SA(X) static_assert (X, #X)
+
+struct A
+{
+  int i;
+  constexpr A(int _i) { i = _i; } // { dg-error "empty body|uninitialized member" }
+};
+
+template <class T>
+struct B
+{
+  T t;
+  constexpr B(T _t): t(_t) { }
+};
+
+B<int> b(1);
+SA(b.t==1);			// { dg-error "non-constant condition|'b'" }
+constexpr B<int> b2(1);
+SA(b2.t==1);
+
+template <class T>
+constexpr T f(T a, T b)
+{
+  typedef T myT;
+  return a + b;
+}
+
+SA(f(1,2)==3);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex4.C
new file mode 100644
index 0000000..4214f5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex4.C
@@ -0,0 +1,16 @@
+// { dg-options "-std=c++0x" }
+
+struct A
+{
+  constexpr A(int) { }
+  constexpr operator int() { return 1; };
+};
+
+template <class T>
+struct B
+{
+  static constexpr A a = A(1);
+  int ar[a];
+};
+
+B<int> b;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-explicit-inst.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-explicit-inst.C
new file mode 100644
index 0000000..8f0da0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-explicit-inst.C
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+
+template<class T> constexpr inline T bar(T x) { return x; }
+
+template short bar(short x); // #EI
+
+constexpr auto yz = bar(0); // OK
+constexpr auto ab = bar(short()); // #1 Error, but should be OK
+constexpr auto mn = bar(short{}); // #2 Error, but should be OK
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-fnptr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-fnptr.C
new file mode 100644
index 0000000..4c84d82
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-fnptr.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+constexpr bool is_negative(int x) { return x < 0; }
+
+constexpr bool check(int x, bool (*p)(int)) { return p(x); }  // #1
+
+static_assert(check(-2, is_negative), "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-function1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-function1.C
new file mode 100644
index 0000000..afe964b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-function1.C
@@ -0,0 +1,10 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+constexpr int veryabs(int x) { return x < 0 ? -x : x; }
+
+constexpr long long_max() { return 2147483647; }
+
+constexpr int verysquare(int x) { return x * x; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-function2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-function2.C
new file mode 100644
index 0000000..5e0c101
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-function2.C
@@ -0,0 +1,50 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// Mess with the builtin by redeclaring.
+constexpr int abs(int x) { return x < 0 ? -x : x; }
+
+extern "C"
+{
+  constexpr float
+  squaref(float x) { return x * x; }
+}
+
+// implicitly inline, already: warn?
+inline constexpr double
+squared(double x) { return x * x; }
+
+constexpr int squarei(int x) { return x * x; }
+extern const int side;
+constexpr int area = squarei(side); // { dg-error "side|argument" }
+// error: squarei(side) is not a constant expression
+
+int next(constexpr int x) // { dg-error "parameter" }
+{ return x + 1; }
+
+constexpr void f(int x)       // { dg-error "return type .void" }
+{ /* ... */ }
+
+constexpr int prev(int x)
+{ return --x; }               // { dg-error "--" }
+
+constexpr int g(int x, int n) // error: body not just ‘‘return expr’’
+{
+   int r = 1;
+   while (--n > 0) r *= x;
+   return r;
+} // { dg-error "not a return-statement" }
+
+constexpr int
+bar(int x, int y) { return x + y + x * y; } // { dg-error "previously" }
+
+int bar(int x, int y)	     // { dg-error "redefinition" }
+{ return x * 2 + 3 * y; }
+
+constexpr int twice(int x);  // { dg-message "never defined" }
+enum { bufsz = twice(256) }; // { dg-error "" } twice() isn’t (yet) defined
+
+constexpr int fac(int x)
+{ return x > 2 ? x * fac(x - 1) : 1; } // OK
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-function3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-function3.C
new file mode 100644
index 0000000..07981fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-function3.C
@@ -0,0 +1,30 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// function template 1
+template<typename T>
+  constexpr int bytesize(T t)
+  { return sizeof (t); }        // OK
+
+char buf[bytesize(0)];          // OK -- not C99 VLA
+
+
+// function template 2
+template<typename _Tp>
+  constexpr _Tp
+  square(_Tp x) { return x; }
+
+// Explicit specialization
+template<>
+  constexpr unsigned long
+  square(unsigned long x) { return x * x; }
+
+// Explicit instantiation
+template int square(int);
+
+class A { };
+template A square(A);
+
+template long square(long);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice.C
new file mode 100644
index 0000000..3b72484
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice.C
@@ -0,0 +1,11 @@
+// We used to crash on this instead of giving a decent error.
+// { dg-options -std=c++0x }
+
+struct A { int i; };
+
+struct B {
+  const A *a;
+  constexpr B(const A& a): a(&a) { }
+};
+
+constexpr B b{A{42}};		// { dg-error "constant|expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist.C
new file mode 100644
index 0000000..6854e73
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist.C
@@ -0,0 +1,65 @@
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+namespace xstd {
+
+typedef decltype(sizeof(char)) size_t;
+
+template<class E>
+class initializer_list {
+private:
+	size_t sz;
+	const E* start;
+
+public:
+	typedef E value_type;
+  typedef const E& reference;
+  typedef const E& const_reference;
+  typedef size_t size_type;
+  typedef const E* iterator;
+  typedef const E* const_iterator;
+
+  constexpr initializer_list() : sz(), start(nullptr) {}
+
+  template<size_t N>
+  constexpr initializer_list(const E(&array)[N]) : sz(N), start(array) {}
+
+  constexpr size_t size() { return sz; }
+
+  constexpr const E* begin() { return start; }
+
+  constexpr const E* end() { return start + sz; }
+};
+
+template<class E, size_t N>
+constexpr initializer_list<E> make_list(const E(&array)[N]) {
+	return initializer_list<E>(array);
+}
+
+template<class E>
+E min(initializer_list<E> list)
+{
+  //	static_assert(list.size() > 0, "Invalid list");
+	auto it = list.begin();
+	E result = *it;
+	for (++it; it != list.end(); ++it) {
+		if (*it < result) {
+			result = *it;
+		}
+	}
+	return result;
+}
+
+}
+
+constexpr int global_i[] = {2, 4, -5, 6, 10};
+constexpr xstd::initializer_list<int> list(global_i);
+#define SA(X) static_assert(X, #X)
+SA(list.size() == 5);
+SA(list.begin()[2] == -5);
+SA(list.end()[-1] == 10);
+
+int main() {
+  if (xstd::min(xstd::make_list(global_i)) != -5)
+    return 1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C
new file mode 100644
index 0000000..ce01f8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C
@@ -0,0 +1,69 @@
+// Negative examples from N3092 (FCD)
+// { dg-options -std=c++0x }
+
+// OK: declaration
+constexpr int square(int x);	// { dg-message "never defined" }
+
+// error: pixel is a type
+constexpr struct pixel {
+  int x;
+  int y;
+  // OK: declaration
+  constexpr pixel(int);
+};				// { dg-error "constexpr" }
+constexpr pixel::pixel(int a)
+// OK: definition
+  : x(square(a)), y(square(a))	// { dg-error "square" }
+{ }
+
+// error: square not defined, so small(2) not constant (5.19), so constexpr
+// not satisfied
+constexpr pixel small(2);	// { dg-error "" }
+
+// error: not for parameters
+int next(constexpr int x) {	// { dg-error "parameter" }
+  return x + 1;
+}
+
+// error: not a definition
+extern constexpr int memsz;	// { dg-error "definition" }
+
+// error: return type is void
+constexpr void f(int x)		// { dg-error "void" }
+{ /* ... */ }
+// error: use of decrement
+constexpr int prev(int x)
+{ return --x; }			// { dg-error "-- x" }
+
+// error: body not just return expr
+constexpr int g(int x, int n) {
+  int r = 1;
+  while (--n > 0) r *= x;
+  return r;
+} // { dg-error "body of constexpr function" }
+
+class debug_flag {
+public:
+  explicit debug_flag(bool);
+  constexpr bool is_on();	// { dg-error "not a literal type" } debug_flag not literal type
+private:
+  bool flag;
+};
+// OK
+constexpr int bar(int x, int y) // { dg-error "previously defined here" }
+{ return x + y + x*y; }
+// ...
+// error: redefinition of bar
+int bar(int x, int y)		// { dg-error "redefinition" }
+{ return x * 2 + 3 * y; }
+
+struct pixel2 {	   // { dg-message "no user-provided default constructor" }
+  int x, y;
+};
+constexpr pixel2 ur = { 1294, 1024 };// OK
+constexpr pixel2 origin;	     // { dg-error "uninitialized const" }
+
+constexpr const int* addr(const int& ir) { return &ir; } // OK
+
+// error, initializer for constexpr variable not a constant
+extern constexpr const int* tp = addr(5); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C
new file mode 100644
index 0000000..0476f90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+struct is_funny {
+  static constexpr bool value = false;
+};
+
+template<class T>
+constexpr T value(T t) noexcept(is_funny<T>::value) { return t; } // Line 7
+
+constexpr bool ok = noexcept(value(42));
+
+static_assert(ok, "Assertion failure");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept2.C
new file mode 100644
index 0000000..95a1443
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept2.C
@@ -0,0 +1,14 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+constexpr T value(T t) { return t; }
+
+template<class T>
+struct is_funny {
+  static constexpr bool value = false;
+};
+
+template<class T>
+void eval() noexcept(value(is_funny<T>::value)) {}
+
+constexpr bool ok = noexcept(eval<int>()); // line 12
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C
new file mode 100644
index 0000000..6e76ea8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept3.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+constexpr int f(int i) { return i; }
+#define SA(X) static_assert (X, #X)
+SA(noexcept(f(42)));
+int j;
+SA(!noexcept(f(j)));
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C
new file mode 100644
index 0000000..119d4e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-noexcept4.C
@@ -0,0 +1,14 @@
+// { dg-options -std=c++0x }
+// A call is noexcept if it is a valid subexpression of a constant
+// expression, even if it is not itself a constant expression.
+
+#define SA(X) static_assert(X,#X)
+
+constexpr const int* f(const int *p) { return p; }
+
+int main()
+{
+  constexpr int i = 42;
+  SA(noexcept(*f(&i)));
+  SA(noexcept(f(&i)));
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-non-const-arg.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-non-const-arg.C
new file mode 100644
index 0000000..2c53595
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-non-const-arg.C
@@ -0,0 +1,24 @@
+// Example from issue 1125 drafting; D() and v were well-formed with the
+// wording approved in Rapperswil, now seems they should be ill-formed.
+// { dg-options "-std=c++0x -pedantic-errors" }
+
+struct B {
+  constexpr B(int x) : i(0) { }    // "x" is unused
+  int i;
+};
+
+int global; // not constant
+
+struct D : B {
+  constexpr D() : B(global) { }   // { dg-error "global|argument" }
+};
+
+struct A2 {
+  constexpr A2(bool b, int x) : m(b ? 42 : x) { }
+  int m;
+};
+
+// ok, constructor call initializes m with the value 42 after substitution
+constexpr int v = A2(true, global).m; // { dg-error "global" }
+// error: initializer for m is "x", which is non-constant
+constexpr int w = A2(false, global).m; // { dg-error "global" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit.C
new file mode 100644
index 0000000..9104c8a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit.C
@@ -0,0 +1,13 @@
+// FIXME this is currently invalid, but seems like it should be OK
+// { dg-options -std=c++0x }
+
+struct A { A() { } };
+
+template<class T>
+constexpr bool ignore(T&&) { return true; }
+
+static_assert(ignore(10), "Error"); // OK
+
+A s;
+
+static_assert(ignore(s), "Error"); // Currently an error
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit2.C
new file mode 100644
index 0000000..21e8bd5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-nonlit2.C
@@ -0,0 +1,19 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  ~A();
+};
+
+template<class T>
+struct W {
+  T t;
+  template<class U>
+  constexpr W(U&& u) : t(u) {}
+};
+
+template <class T>
+constexpr W<T> make_w(T& w) { return W<T>(w); }
+
+A a;
+constexpr auto w = make_w(a);	// { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C
new file mode 100644
index 0000000..7ac53db
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C
@@ -0,0 +1,6 @@
+// { dg-options -std=c++0x }
+
+constexpr int zero() { return 0; }
+
+void* ptr1 = zero(); // #1
+constexpr void* ptr2 = zero(); // #2
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C
new file mode 100644
index 0000000..c635fd0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C
@@ -0,0 +1,31 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.5.2 semantics
+
+// p 1 constexpr specifier
+// objects, static const data
+struct A1 { };	   // { dg-message "no user-provided default constructor" }
+
+constexpr int i1 = 1024;
+constexpr A1 a1 = A1();
+
+// error: not a definition
+extern constexpr int i2; // { dg-error "definition" }
+
+// error: missing initializer
+constexpr A1 a2; // { dg-error "uninitialized const" }
+
+// error: duplicate cv
+const constexpr A1 a3 = A1(); // { dg-error "both .const. and .constexpr. cannot" }
+
+volatile constexpr A1 a4 = A1(); // { dg-error "both .volatile. and .constexpr. cannot" }
+
+// error: on type declaration
+constexpr struct pixel
+{
+  int x;
+  int y;
+};		     // { dg-error "cannot be used for type declarations" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-object2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-object2.C
new file mode 100644
index 0000000..3590bb8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-object2.C
@@ -0,0 +1,16 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+constexpr int verysquare(int x) { return x * x; }
+
+const double mass = 9.8;
+constexpr double energy = mass * verysquare(56.6); // { dg-error "mass" "" { xfail *-*-* } }
+
+int arr[(int)mass];		// { dg-error "mass" "" { xfail *-*-* } }
+
+float array[verysquare(9)];         // OK -- not C99 VLA
+
+extern const int medium;
+const int high = verysquare(medium); // OK -- dynamic initialization
+
+enum { Max = verysquare(7) };      // OK
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow.C
new file mode 100644
index 0000000..9b3b1fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow.C
@@ -0,0 +1,6 @@
+// { dg-options "-std=c++0x -w" }
+
+#include <limits.h>
+extern constexpr int max_s = INT_MAX + 1;  // { dg-error "" }
+extern constexpr unsigned max_u = UINT_MAX + 1u;  // OK
+extern constexpr int abs_s = -INT_MIN;  // { dg-error "" } overflows on 2's complement machines
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-pedantic.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-pedantic.C
new file mode 100644
index 0000000..dc393d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-pedantic.C
@@ -0,0 +1,16 @@
+// The FCD doesn't allow typedefs and static_assert in constexpr functions,
+// but it should.
+// { dg-options "-std=c++0x -pedantic" }
+
+template <class T>
+constexpr T f(T t)
+{
+  typedef T T2;			     // { dg-warning "constexpr" "" { xfail *-*-* } }
+  static_assert (T2(0) == T(0), ""); // { dg-warning "constexpr" "" { xfail *-*-* } }
+  return t;
+}
+
+int main()
+{
+  constexpr int i = f(42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-pos1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-pos1.C
new file mode 100644
index 0000000..775080a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-pos1.C
@@ -0,0 +1,60 @@
+// Positive examples from N3092 (FCD)
+// { dg-options -std=c++0x }
+
+#define SA(X) static_assert(X, #X)
+
+constexpr int bufsz = 1024; // OK: definition
+SA (bufsz == 1024);
+
+constexpr int square(int x); // OK: declaration
+
+struct pixel {
+  int x;
+  int y;
+  // OK: declaration
+  constexpr pixel(int);
+};
+constexpr pixel::pixel(int a) // OK: definition
+  : x(square(a)), y(square(a))
+{ }
+
+constexpr int square(int x) // OK: definition
+{ return x * x; }
+
+constexpr pixel large(4); // OK: square defined
+SA(large.x == 16 && large.y==16);
+
+constexpr long long_max() // OK
+{ return 2147483647; }
+
+SA(long_max() == 2147483647);
+
+constexpr int abs(int x) // OK
+{ return x < 0 ? -x : x; }
+
+SA(abs(-1) == 1);
+SA(abs(24) == 24);
+
+struct Length {
+  explicit constexpr Length(int i = 0) : val(i) { }
+private:
+  int val;
+};
+
+constexpr Length l1;
+constexpr Length l2(12);
+
+struct pixel2 {
+  int x, y;
+};
+constexpr pixel2 ur = { 1294, 1024 };// OK
+
+SA(ur.x == 1294 && ur.y == 1024);
+
+constexpr const int* addr(const int& ir) { return &ir; } // OK
+static const int x = 5;
+extern constexpr const int* xp = addr(x); // OK: (const int*)&(const int&)x
+					  // is an address contant expression
+SA(xp == &x);
+extern constexpr int x2 = *addr(5);
+SA(x2 == 5);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-potential1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-potential1.C
new file mode 100644
index 0000000..e933506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-potential1.C
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+// We decided in Rapperswil that it's OK if any value of decide can produce
+// a constant expression.
+
+constexpr int may_throw(bool decide) {
+  return decide ? 42 : throw -1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrmem.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrmem.C
new file mode 100644
index 0000000..f6ed2f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrmem.C
@@ -0,0 +1,20 @@
+// { dg-options -std=c++0x }
+
+struct C { // literal type
+  int m;
+  int n;
+  constexpr C(int m) : m(m), n(-m) {}
+  constexpr bool is_neg() { return m < 0; }
+};
+
+constexpr bool check1(const C& c, int C:: *pm) { return c.*pm < 0; } // #1
+
+constexpr bool check2(const C* pc, bool (C::*pm)() const) { return
+(pc->*pm)(); } // #2
+
+constexpr C c(-1);
+
+static_assert(!check1(c, &C::n), "Error");
+static_assert(check1(c, &C::m), "Error");
+
+static_assert(check2(&c, &C::is_neg), "Error");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-pure.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-pure.C
new file mode 100644
index 0000000..e17e02a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-pure.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  virtual void f() = 0;
+};
+
+struct B: A
+{
+  void f() { }
+};
+
+B b;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static.C
new file mode 100644
index 0000000..8ed2b5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static.C
@@ -0,0 +1,24 @@
+// Test for constant initialization of non-literal class (e.g. mutex)
+// { dg-options "-std=c++0x -save-temps" }
+// { dg-do run }
+
+struct A
+{
+  int i;
+  constexpr A(int _i): i(_i) { }
+  A(const A&);		       // non-trivial copy ctor makes A non-literal
+};
+
+A a(42);	    // constexpr constructor allows constant initialization
+A ar[3] = { { 1 }, { 2 }, { 3 } };
+// { dg-final { scan-assembler-not "static_initialization" } }
+// { dg-final cleanup-saved-temps }
+
+int main()
+{
+  if (a.i != 42
+      || ar[0].i != 1
+      || ar[1].i != 2
+      || ar[2].i != 3)
+    return 1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static2.C
new file mode 100644
index 0000000..67c3530
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static2.C
@@ -0,0 +1,11 @@
+// { dg-options -std=c++0x }
+struct IsLiteral {};
+
+struct ShouldBeLiteral {
+  constexpr ShouldBeLiteral(int){}
+};
+
+struct StaticDataMember {
+  static constexpr IsLiteral one = IsLiteral(); // #1
+  static constexpr ShouldBeLiteral two= ShouldBeLiteral(-1); // #2
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static3.C
new file mode 100644
index 0000000..dccdc85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static3.C
@@ -0,0 +1,18 @@
+// Test for constant initialization of class with vtable
+// { dg-options "-std=c++0x -save-temps" }
+// { dg-final { scan-assembler-not "static_initialization" } }
+// { dg-final cleanup-saved-temps }
+// { dg-do run }
+
+int r = 1;
+// implicit default constructor for A and B is constexpr
+struct A { virtual void f() {} };
+struct B: A { virtual void f() { r = 0; } };
+
+B b;
+
+int main()
+{
+  b.f();
+  return r;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static4.C
new file mode 100644
index 0000000..8189fc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static4.C
@@ -0,0 +1,20 @@
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+extern "C" void abort ();
+extern int ar[2];
+
+int f()
+{
+  if (ar[0] != 42 || ar[1] != 0)
+    abort ();
+  return 1;
+}
+
+int i = f();
+
+int ar[2] = { 42, i };
+
+int main()
+{
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static5.C
new file mode 100644
index 0000000..cb553a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static5.C
@@ -0,0 +1,17 @@
+// { dg-options -std=c++0x }
+
+template <class T>
+struct A
+{
+  constexpr static T t;
+};
+template <class T>
+constexpr T A<T>::t = T();	// { dg-error "not literal" }
+
+struct B
+{
+  ~B();
+};
+
+B b = A<B>::t;
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static6.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static6.C
new file mode 100644
index 0000000..a34704d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static6.C
@@ -0,0 +1,21 @@
+// { dg-options -std=c++0x }
+
+struct B
+{
+  constexpr operator int() { return 4; }
+};
+
+template <int I>
+struct C;
+
+template<>
+struct C<4> { typedef int TP; };
+
+template <class T>
+struct A
+{
+  constexpr static B t = B();
+  C<t>::TP tp;
+};
+
+A<B> a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
new file mode 100644
index 0000000..e76d00d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
@@ -0,0 +1,5 @@
+// { dg-options -std=c++0x }
+
+constexpr char c1 = "hi"[1];
+constexpr char c2 = "hi"[2];
+constexpr char c3 = "hi"[3];	// { dg-error "out of bound" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-switch.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-switch.C
new file mode 100644
index 0000000..d229304
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-switch.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+constexpr T value(T t = T()) { return t; }
+
+enum us_enum { us_item = value<short>() }; // OK
+
+void func(us_enum n) {
+  switch (n) {
+  case value(us_item): ; // #1 Error
+  default: ;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
new file mode 100644
index 0000000..0c8c73d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
@@ -0,0 +1,13 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  constexpr operator double() { return 1.0; }
+};
+
+template <int I>
+struct B
+{ };
+
+constexpr A a { };
+B<a> b;				// { dg-error "template argument|invalid type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C
new file mode 100644
index 0000000..345b240
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-throw.C
@@ -0,0 +1,8 @@
+// { dg-options -std=c++0x }
+
+constexpr int may_throw(bool decide) {
+	return decide ? 42 : throw -1; // { dg-error "throw" }
+}
+
+constexpr int x = may_throw(false); // { dg-error "may_throw" }
+constexpr int y = may_throw(true);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-typeid.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-typeid.C
new file mode 100644
index 0000000..b523bb3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-typeid.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++0x }
+
+#include <typeinfo>
+
+struct A { virtual void f(); };
+
+extern constexpr const std::type_info* p1 = &typeid(int);
+extern constexpr const std::type_info* p2 = &typeid(A);
+// typeid-expression whose operand is of a polymorphic class type
+extern constexpr const std::type_info* p3 = &typeid((A())); // { dg-error "" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C
new file mode 100644
index 0000000..b461305
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union.C
@@ -0,0 +1,16 @@
+// Test that we don't have to deal with type punning
+// FIXME Mike Miller thinks it should work
+// { dg-options -std=c++0x }
+
+union U
+{
+  float f;
+  unsigned char ca[sizeof(float)];
+};
+
+constexpr U u = { 1.0 };
+constexpr float f = u.f;
+constexpr unsigned char c = u.ca[0]; // { dg-error "U::ca" }
+
+constexpr double d = 1.0;
+constexpr unsigned char c2 = (unsigned char&)d; // { dg-error "char. glvalue" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-value.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-value.C
new file mode 100644
index 0000000..85799d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-value.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++0x }
+
+struct HopefullyLiteral {
+  HopefullyLiteral() = default; // Should be a constexpr c'tor as of 12.1/6 and 8.4.2/4
+};
+
+constexpr HopefullyLiteral var1{}; // OK
+constexpr HopefullyLiteral var2 = HopefullyLiteral{}; // #1
+constexpr HopefullyLiteral var3 = HopefullyLiteral(); // #2
+constexpr HopefullyLiteral var4 = HopefullyLiteral(var3); // #3
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-value2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-value2.C
new file mode 100644
index 0000000..1b0e28f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-value2.C
@@ -0,0 +1,19 @@
+// { dg-options -std=c++0x }
+
+template<class T>
+constexpr T value_init() { return T(); }
+
+template<class T>
+constexpr inline T bar(T x) { return x; }
+
+union EmptyUnion {};
+union Union1 { int i; };
+union Union3 { double d; int i; char* c; };
+
+constexpr auto u1 = value_init<EmptyUnion>();
+constexpr auto u2 = value_init<Union1>();
+constexpr auto u3 = value_init<Union3>();
+constexpr auto u4 = bar(EmptyUnion{});
+constexpr auto u5 = bar(Union1{});
+constexpr auto u6 = bar(Union3{});
+constexpr auto u7 = bar(u1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-variadic.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-variadic.C
new file mode 100644
index 0000000..5d0ad05
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-variadic.C
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+template<class... T>
+constexpr bool variadics(T&&...) { return true; }
+
+struct IsLiteral {};
+
+constexpr bool variadic_var = variadics(0, true, 1.2, IsLiteral{}); // Error, so below
+
+int main() {}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist5.C b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
index 958007c..32caac3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
@@ -23,5 +23,5 @@ int k {}; // initialize to 0
 // PR c++/36963
 double d = 1.1;
 float fa[] = { d, 1.1 };      // { dg-error "narrowing conversion of 'd'" }
-const double d2 = 1.1;
+constexpr double d2 = 1.1;
 float fa2[] = { d2, 1.1 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/static_assert3.C b/gcc/testsuite/g++.dg/cpp0x/static_assert3.C
index 69f93ab..1ff2ffc 100644
--- a/gcc/testsuite/g++.dg/cpp0x/static_assert3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/static_assert3.C
@@ -1,3 +1,4 @@
 // { dg-options "-std=c++0x" }
 static_assert(7 / 0, "X"); // { dg-error "non-constant condition" }
 // { dg-warning "division by zero" "" { target *-*-* } 2 }
+// { dg-error "7 / 0.. is not a constant expression" "" { target *-*-* } 2 }
diff --git a/gcc/testsuite/g++.dg/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index b075fc1..23d3454 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];
+    int x[i];		     // { dg-error "constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/constant4.C b/gcc/testsuite/g++.dg/parse/constant4.C
index d69f60b..b2c112c 100644
--- a/gcc/testsuite/g++.dg/parse/constant4.C
+++ b/gcc/testsuite/g++.dg/parse/constant4.C
@@ -18,7 +18,7 @@ void Foo ()
   
   static const unsigned J = X<T>::J;
   
-  Y<J> j; // { dg-error "non-constant" "" }
+  Y<J> j; // { dg-error "constant" "" }
 }
 
 struct A 
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 6116eb0..a5a142c 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];
+int x[A <int>::i];		// { dg-error "constant-expression" }
diff --git a/gcc/testsuite/g++.dg/template/arg5.C b/gcc/testsuite/g++.dg/template/arg5.C
index 3d67143..87cbd02 100644
--- a/gcc/testsuite/g++.dg/template/arg5.C
+++ b/gcc/testsuite/g++.dg/template/arg5.C
@@ -5,5 +5,5 @@ template<bool> struct A;
 
 template<int> void foo()
 {
-  A<__builtin_constant_p(.)> a;  // { dg-error "template argument" }
+  A<__builtin_constant_p(.)> a;  // { dg-error "template argument|invalid" }
 }
diff --git a/gcc/testsuite/g++.dg/template/non-dependent10.C b/gcc/testsuite/g++.dg/template/non-dependent10.C
index 0adac25..1891cad 100644
--- a/gcc/testsuite/g++.dg/template/non-dependent10.C
+++ b/gcc/testsuite/g++.dg/template/non-dependent10.C
@@ -18,5 +18,5 @@ struct X
 template <class T>
 struct Foo
 {
-  X<&S::f> x;	// { dg-error "convert|no type" }
+  X<&S::f> x;	// { dg-error "convert|no matches" }
 };
diff --git a/gcc/testsuite/g++.dg/template/qualified-id3.C b/gcc/testsuite/g++.dg/template/qualified-id3.C
index d97ef5c..1fc1cc3 100644
--- a/gcc/testsuite/g++.dg/template/qualified-id3.C
+++ b/gcc/testsuite/g++.dg/template/qualified-id3.C
@@ -3,7 +3,7 @@
 template <const int N> struct A { };
 template <class T> struct B {
   static const int c;
-  typedef A<B<T>::c> C;		// { dg-error "non-constant" }
+  typedef A<B<T>::c> C;		// { dg-error "constant expression" }
 };
 template <class T> const int B<T>::c = sizeof (T);
 
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
index 78f4348..17bd067 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -13,7 +13,7 @@ enum e {
      in the standard).  */
   E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
   E3 = 1 / 0, /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
+  /* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
   /* 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" } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
index fa45eeb..ce03a97 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -13,7 +13,7 @@ enum e {
      in the standard).  */
   E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
   E3 = 1 / 0, /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
+  /* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
   /* 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" } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
index ae06a80..0c916d0 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -13,7 +13,7 @@ enum e {
      in the standard).  */
   E2 = 2 || 1 / 0, /* { dg-bogus "warning: division by zero" "" { xfail *-*-* } 14 } */
   E3 = 1 / 0, /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E3' is not an integer constant" "enum error" { target *-*-* } 15 } */
+  /* { dg-error "enumerator value for 'E3' is not an integer constant|not a constant expression" "enum error" { target *-*-* } 15 } */
   /* 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" } */
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash10.C b/gcc/testsuite/g++.old-deja/g++.pt/crash10.C
index a66450f..af0e919 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash10.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash10.C
@@ -4,7 +4,7 @@ template<int M, int N>
 class GCD {
 public:
   enum { val = (N == 0) ? M : GCD<N, M % N>::val }; // { dg-warning "division" "division" }
-// { dg-error "not a valid" "valid" { target *-*-* } 6 }
+// { dg-error "constant expression" "valid" { target *-*-* } 6 }
 };
 
 int main() {
diff --git a/libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc b/libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc
index 252265c..c761769 100644
--- a/libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/ratio/cons/cons_overflow_neg.cc
@@ -51,3 +51,6 @@ test04()
 // { dg-error "instantiated from here" "" { target *-*-* } 46 }
 // { dg-error "denominator cannot be zero" "" { target *-*-* } 153 }
 // { dg-error "out of range" "" { target *-*-* } 154 }
+// { dg-error "constant expression" "" { target *-*-* } 59 }
+// { dg-error "not a member" "" { target *-*-* } 162 }
+// { dg-error "not a valid template argument" "" { target *-*-* } 164 }
H.J. Lu - Nov. 2, 2010, 8:51 p.m.
On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
> The rest of these patches I'm not applying immediately because the last one
> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
> apply the others without the last one; I'm just sending them to the list now
> to make the end of Stage 1.
>
> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
> the new decl_constant_var_p which also allows constexpr variables, adjusts
> when-used template instantiation to require immediate instantiation of
> constexpr functions.
>
> constexpr-register.patch: Handles storing the definition of constexpr
> functions for later expansion.
>
> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
> constant expressions.
>
> constexpr-integrate.patch: Integrates the C++0x constant expression
> semantics into the rest of the compiler.
>
> The last patch in particular still needs some work; in particular, I still
> need to sort out the relationship between constant expression evaluation and
> value_dependent_expression_p.  I think this will just mean using
> potential_constant_expression, but it still needs to happen; I think this
> can be cleaned up in stage 3.
>

The last patch caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
H.J. Lu - Nov. 7, 2010, 3:51 p.m.
On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>> The rest of these patches I'm not applying immediately because the last one
>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>> apply the others without the last one; I'm just sending them to the list now
>> to make the end of Stage 1.
>>
>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>> when-used template instantiation to require immediate instantiation of
>> constexpr functions.
>>
>> constexpr-register.patch: Handles storing the definition of constexpr
>> functions for later expansion.
>>
>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>> constant expressions.
>>
>> constexpr-integrate.patch: Integrates the C++0x constant expression
>> semantics into the rest of the compiler.
>>
>> The last patch in particular still needs some work; in particular, I still
>> need to sort out the relationship between constant expression evaluation and
>> value_dependent_expression_p.  I think this will just mean using
>> potential_constant_expression, but it still needs to happen; I think this
>> can be cleaned up in stage 3.
>>
>
> The last patch caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>

It also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
H.J. Lu - Nov. 29, 2010, 2:58 p.m.
On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>> The rest of these patches I'm not applying immediately because the last one
>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>> apply the others without the last one; I'm just sending them to the list now
>>> to make the end of Stage 1.
>>>
>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>> when-used template instantiation to require immediate instantiation of
>>> constexpr functions.
>>>
>>> constexpr-register.patch: Handles storing the definition of constexpr
>>> functions for later expansion.
>>>
>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>> constant expressions.
>>>
>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>> semantics into the rest of the compiler.
>>>
>>> The last patch in particular still needs some work; in particular, I still
>>> need to sort out the relationship between constant expression evaluation and
>>> value_dependent_expression_p.  I think this will just mean using
>>> potential_constant_expression, but it still needs to happen; I think this
>>> can be cleaned up in stage 3.
>>>
>>
>> The last patch caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>
>
> It also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>

The second patch caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46701
H.J. Lu - Nov. 29, 2010, 5:37 p.m.
On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>> The rest of these patches I'm not applying immediately because the last one
>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>> apply the others without the last one; I'm just sending them to the list now
>>> to make the end of Stage 1.
>>>
>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>> when-used template instantiation to require immediate instantiation of
>>> constexpr functions.
>>>
>>> constexpr-register.patch: Handles storing the definition of constexpr
>>> functions for later expansion.
>>>
>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>> constant expressions.
>>>
>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>> semantics into the rest of the compiler.
>>>
>>> The last patch in particular still needs some work; in particular, I still
>>> need to sort out the relationship between constant expression evaluation and
>>> value_dependent_expression_p.  I think this will just mean using
>>> potential_constant_expression, but it still needs to happen; I think this
>>> can be cleaned up in stage 3.
>>>
>>
>> The last patch caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>
>
> It also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>

It also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46626
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46670
H.J. Lu - Jan. 7, 2011, 2:48 p.m.
On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
> The rest of these patches I'm not applying immediately because the last one
> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
> apply the others without the last one; I'm just sending them to the list now
> to make the end of Stage 1.
>
> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
> the new decl_constant_var_p which also allows constexpr variables, adjusts
> when-used template instantiation to require immediate instantiation of
> constexpr functions.
>
> constexpr-register.patch: Handles storing the definition of constexpr
> functions for later expansion.
>
> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
> constant expressions.
>
> constexpr-integrate.patch: Integrates the C++0x constant expression
> semantics into the rest of the compiler.
>
> The last patch in particular still needs some work; in particular, I still
> need to sort out the relationship between constant expression evaluation and
> value_dependent_expression_p.  I think this will just mean using
> potential_constant_expression, but it still needs to happen; I think this
> can be cleaned up in stage 3.
>
> The other remaining cleanup is to switch the C++ front end over to a
> c_fully_fold type model of delayed folding; I had originally expected to do
> that early in development, but it turned out to be more complicated than I
> expected, so I decided to finish the functionality first.  This will be
> necessary to be fully correct in deciding what is or is not a constant
> expression.  I do not plan to do this for GCC 4.6.
>
> Tested x86_64-pc-linux-gnu, not applied quite yet.
>
> commit e1c3c7a78bb1d0b58389ba15b13871d2da9c05a9
> Author: Jason Merrill <jason@redhat.com>
> Date:   Tue Oct 26 19:03:56 2010 -0400
>
>        * decl2.c (decl_constant_var_p): New fn.
>        (decl_maybe_constant_var_p): New fn.
>        (mark_used): Rework instantiation of things needed for constant
>        expressions.
>        * cp-tree.h: Declare new fns.
>        * pt.c (instantiate_decl): Handle cp_unevaluated_operand.
>        (always_instantiate_p): Use decl_maybe_constant_var_p.
>        (instantiate_decl): Don't defer constexpr functions.
>        * repo.c (repo_emit_p): Use decl_maybe_constant_var_p.
>        * semantics.c (finish_id_expression): Use decl_constant_var_p.
>        Check for valid name in constant expr after mark_used.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47207
H.J. Lu - Jan. 7, 2011, 2:53 p.m.
On Mon, Nov 29, 2010 at 9:37 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>>> The rest of these patches I'm not applying immediately because the last one
>>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>>> apply the others without the last one; I'm just sending them to the list now
>>>> to make the end of Stage 1.
>>>>
>>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>>> when-used template instantiation to require immediate instantiation of
>>>> constexpr functions.
>>>>
>>>> constexpr-register.patch: Handles storing the definition of constexpr
>>>> functions for later expansion.
>>>>
>>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>>> constant expressions.
>>>>
>>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>>> semantics into the rest of the compiler.
>>>>
>>>> The last patch in particular still needs some work; in particular, I still
>>>> need to sort out the relationship between constant expression evaluation and
>>>> value_dependent_expression_p.  I think this will just mean using
>>>> potential_constant_expression, but it still needs to happen; I think this
>>>> can be cleaned up in stage 3.
>>>>
>>>
>>> The last patch caused:
>>>
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>>
>>
>> It also caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>>
>
> It also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46626
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46670
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46557
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46977
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47020
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47172
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47199
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47200
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47206
H.J. Lu - Jan. 7, 2011, 2:57 p.m.
On Fri, Jan 7, 2011 at 6:48 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>> The rest of these patches I'm not applying immediately because the last one
>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>> apply the others without the last one; I'm just sending them to the list now
>> to make the end of Stage 1.
>>
>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>> when-used template instantiation to require immediate instantiation of
>> constexpr functions.
>>
>> constexpr-register.patch: Handles storing the definition of constexpr
>> functions for later expansion.
>>
>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>> constant expressions.
>>
>> constexpr-integrate.patch: Integrates the C++0x constant expression
>> semantics into the rest of the compiler.
>>
>> The last patch in particular still needs some work; in particular, I still
>> need to sort out the relationship between constant expression evaluation and
>> value_dependent_expression_p.  I think this will just mean using
>> potential_constant_expression, but it still needs to happen; I think this
>> can be cleaned up in stage 3.
>>
>> The other remaining cleanup is to switch the C++ front end over to a
>> c_fully_fold type model of delayed folding; I had originally expected to do
>> that early in development, but it turned out to be more complicated than I
>> expected, so I decided to finish the functionality first.  This will be
>> necessary to be fully correct in deciding what is or is not a constant
>> expression.  I do not plan to do this for GCC 4.6.
>>
>> Tested x86_64-pc-linux-gnu, not applied quite yet.
>>
>> commit e1c3c7a78bb1d0b58389ba15b13871d2da9c05a9
>> Author: Jason Merrill <jason@redhat.com>
>> Date:   Tue Oct 26 19:03:56 2010 -0400
>>
>>        * decl2.c (decl_constant_var_p): New fn.
>>        (decl_maybe_constant_var_p): New fn.
>>        (mark_used): Rework instantiation of things needed for constant
>>        expressions.
>>        * cp-tree.h: Declare new fns.
>>        * pt.c (instantiate_decl): Handle cp_unevaluated_operand.
>>        (always_instantiate_p): Use decl_maybe_constant_var_p.
>>        (instantiate_decl): Don't defer constexpr functions.
>>        * repo.c (repo_emit_p): Use decl_maybe_constant_var_p.
>>        * semantics.c (finish_id_expression): Use decl_constant_var_p.
>>        Check for valid name in constant expr after mark_used.
>>
>
> This caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47207
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47208
H.J. Lu - Jan. 16, 2011, 6:18 p.m.
On Fri, Jan 7, 2011 at 6:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Nov 29, 2010 at 9:37 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>> The rest of these patches I'm not applying immediately because the last one
>>>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>>>> apply the others without the last one; I'm just sending them to the list now
>>>>> to make the end of Stage 1.
>>>>>
>>>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>>>> when-used template instantiation to require immediate instantiation of
>>>>> constexpr functions.
>>>>>
>>>>> constexpr-register.patch: Handles storing the definition of constexpr
>>>>> functions for later expansion.
>>>>>
>>>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>>>> constant expressions.
>>>>>
>>>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>>>> semantics into the rest of the compiler.
>>>>>
>>>>> The last patch in particular still needs some work; in particular, I still
>>>>> need to sort out the relationship between constant expression evaluation and
>>>>> value_dependent_expression_p.  I think this will just mean using
>>>>> potential_constant_expression, but it still needs to happen; I think this
>>>>> can be cleaned up in stage 3.
>>>>>
>>>>
>>>> The last patch caused:
>>>>
>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>>>
>>>
>>> It also caused:
>>>
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>>>
>>
>> It also caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46626
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46670
>>
>
> This also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46557
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46977
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47020
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47172
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47199
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47200
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47206
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47317
H.J. Lu - Jan. 27, 2011, 3:35 a.m.
On Sun, Jan 16, 2011 at 10:18 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Jan 7, 2011 at 6:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Nov 29, 2010 at 9:37 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>>> The rest of these patches I'm not applying immediately because the last one
>>>>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>>>>> apply the others without the last one; I'm just sending them to the list now
>>>>>> to make the end of Stage 1.
>>>>>>
>>>>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>>>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>>>>> when-used template instantiation to require immediate instantiation of
>>>>>> constexpr functions.
>>>>>>
>>>>>> constexpr-register.patch: Handles storing the definition of constexpr
>>>>>> functions for later expansion.
>>>>>>
>>>>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>>>>> constant expressions.
>>>>>>
>>>>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>>>>> semantics into the rest of the compiler.
>>>>>>
>>>>>> The last patch in particular still needs some work; in particular, I still
>>>>>> need to sort out the relationship between constant expression evaluation and
>>>>>> value_dependent_expression_p.  I think this will just mean using
>>>>>> potential_constant_expression, but it still needs to happen; I think this
>>>>>> can be cleaned up in stage 3.
>>>>>>
>>>>>
>>>>> The last patch caused:
>>>>>
>>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>>>>
>>>>
>>>> It also caused:
>>>>
>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>>>>
>>>
>>> It also caused:
>>>
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46626
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46670
>>>
>>
>> This also caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46557
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46977
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47020
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47172
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47199
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47200
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47206
>>
>
> This also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47317
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47482
H.J. Lu - Jan. 28, 2011, 3:27 a.m.
On Wed, Jan 26, 2011 at 7:35 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Jan 16, 2011 at 10:18 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Fri, Jan 7, 2011 at 6:53 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Mon, Nov 29, 2010 at 9:37 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Sun, Nov 7, 2010 at 7:51 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>> On Tue, Nov 2, 2010 at 1:51 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>>> On Sun, Oct 31, 2010 at 7:29 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>>>> The rest of these patches I'm not applying immediately because the last one
>>>>>>> depends on my fold_indirect_ref_1 patch, and it doesn't really make sense to
>>>>>>> apply the others without the last one; I'm just sending them to the list now
>>>>>>> to make the end of Stage 1.
>>>>>>>
>>>>>>> decl_constant_var.patch: Replaces uses of DECL_INTEGRAL_CONSTANT_VAR_P with
>>>>>>> the new decl_constant_var_p which also allows constexpr variables, adjusts
>>>>>>> when-used template instantiation to require immediate instantiation of
>>>>>>> constexpr functions.
>>>>>>>
>>>>>>> constexpr-register.patch: Handles storing the definition of constexpr
>>>>>>> functions for later expansion.
>>>>>>>
>>>>>>> constexpr-eval.patch: Handles the actual compile-time evaluation of C++0x
>>>>>>> constant expressions.
>>>>>>>
>>>>>>> constexpr-integrate.patch: Integrates the C++0x constant expression
>>>>>>> semantics into the rest of the compiler.
>>>>>>>
>>>>>>> The last patch in particular still needs some work; in particular, I still
>>>>>>> need to sort out the relationship between constant expression evaluation and
>>>>>>> value_dependent_expression_p.  I think this will just mean using
>>>>>>> potential_constant_expression, but it still needs to happen; I think this
>>>>>>> can be cleaned up in stage 3.
>>>>>>>
>>>>>>
>>>>>> The last patch caused:
>>>>>>
>>>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46277
>>>>>>
>>>>>
>>>>> It also caused:
>>>>>
>>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46335
>>>>>
>>>>
>>>> It also caused:
>>>>
>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46626
>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46670
>>>>
>>>
>>> This also caused:
>>>
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46557
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46977
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47020
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47172
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47199
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47200
>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47206
>>>
>>
>> This also caused:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47317
>>
>
> This also caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47482
>
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47503

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e5ea232..bc4eb46 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4882,6 +4882,8 @@  extern void constrain_class_visibility		(tree);
 extern void import_export_decl			(tree);
 extern tree build_cleanup			(tree);
 extern tree build_offset_ref_call_from_tree	(tree, VEC(tree,gc) **);
+extern bool decl_constant_var_p			(tree);
+extern bool decl_maybe_constant_var_p		(tree);
 extern void check_default_args			(tree);
 extern void mark_used				(tree);
 extern void finish_static_data_member_decl	(tree, tree, bool, tree, int);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 13fa5f6..3f492bb 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3526,6 +3526,60 @@  decl_defined_p (tree decl)
     }
 }
 
+/* Nonzero for a VAR_DECL whose value can be used in a constant expression.
+
+      [expr.const]
+
+      An integral constant-expression can only involve ... const
+      variables of integral or enumeration types initialized with
+      constant expressions ...
+
+      C++0x also allows constexpr variables and temporaries initialized
+      with constant expressions.  We handle the former here, but the latter
+      are just folded away in cxx_eval_constant_expression.
+
+   The standard does not require that the expression be non-volatile.
+   G++ implements the proposed correction in DR 457.  */
+
+bool
+decl_constant_var_p (tree decl)
+{
+  bool ret;
+  tree type = TREE_TYPE (decl);
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+  if (DECL_DECLARED_CONSTEXPR_P (decl))
+    ret = true;
+  else if (CP_TYPE_CONST_NON_VOLATILE_P (type)
+	   && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+    {
+      /* We don't know if a template static data member is initialized with
+	 a constant expression until we instantiate its initializer.  */
+      mark_used (decl);
+      ret = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl);
+    }
+  else
+    ret = false;
+
+  gcc_assert (!ret || DECL_INITIAL (decl));
+  return ret;
+}
+
+/* Returns true if DECL could be a symbolic constant variable, depending on
+   its initializer.  */
+
+bool
+decl_maybe_constant_var_p (tree decl)
+{
+  tree type = TREE_TYPE (decl);
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+  if (DECL_DECLARED_CONSTEXPR_P (decl))
+    return true;
+  return (CP_TYPE_CONST_NON_VOLATILE_P (type)
+	  && INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+}
+
 /* Complain that DECL uses a type with no linkage but is never defined.  */
 
 static void
@@ -4074,8 +4128,6 @@  possibly_inlined_p (tree decl)
 void
 mark_used (tree decl)
 {
-  HOST_WIDE_INT saved_processing_template_decl = 0;
-
   /* If DECL is a BASELINK for a single function, then treat it just
      like the DECL for the function.  Otherwise, if the BASELINK is
      for an overloaded function, we don't know which function was
@@ -4113,9 +4165,6 @@  mark_used (tree decl)
 	error_at (DECL_SOURCE_LOCATION (decl), "declared here");
       return;
     }
-  /* If we don't need a value, then we don't need to synthesize DECL.  */
-  if (cp_unevaluated_operand != 0)
-    return;
 
   /* We can only check DECL_ODR_USED on variables or functions with
      DECL_LANG_SPECIFIC set, and these are also the only decls that we
@@ -4139,31 +4188,39 @@  mark_used (tree decl)
       return;
     }
 
-  /* Normally, we can wait until instantiation-time to synthesize
-     DECL.  However, if DECL is a static data member initialized with
-     a constant, we need the value right now because a reference to
-     such a data member is not value-dependent.  */
-  if (TREE_CODE (decl) == VAR_DECL
-      && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
-      && DECL_CLASS_SCOPE_P (decl))
+  /* Normally, we can wait until instantiation-time to synthesize DECL.
+     However, if DECL is a static data member initialized with a constant
+     or a constexpr function, we need it right now because a reference to
+     such a data member or a call to such function is not value-dependent.  */
+  if ((decl_maybe_constant_var_p (decl)
+       || (TREE_CODE (decl) == FUNCTION_DECL
+	   && DECL_DECLARED_CONSTEXPR_P (decl)))
+      && !DECL_INITIAL (decl)
+      && DECL_LANG_SPECIFIC (decl)
+      && DECL_TEMPLATE_INSTANTIATION (decl))
     {
-      /* Don't try to instantiate members of dependent types.  We
-	 cannot just use dependent_type_p here because this function
-	 may be called from fold_non_dependent_expr, and then we may
-	 see dependent types, even though processing_template_decl
-	 will not be set.  */
-      if (CLASSTYPE_TEMPLATE_INFO ((DECL_CONTEXT (decl)))
-	  && uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl))))
-	return;
-      /* Pretend that we are not in a template, even if we are, so
-	 that the static data member initializer will be processed.  */
-      saved_processing_template_decl = processing_template_decl;
-      processing_template_decl = 0;
+      /* Instantiating a function will result in garbage collection.  We
+	 must treat this situation as if we were within the body of a
+	 function so as to avoid collecting live data only referenced from
+	 the stack (such as overload resolution candidates).  */
+      ++function_depth;
+      instantiate_decl (decl, /*defer_ok=*/false,
+			/*expl_inst_class_mem_p=*/false);
+      --function_depth;
     }
 
+  /* If we don't need a value, then we don't need to synthesize DECL.  */
+  if (cp_unevaluated_operand != 0)
+    return;
+
   if (processing_template_decl)
     return;
 
+  /* Check this too in case we're within fold_non_dependent_expr.  */
+  if (DECL_TEMPLATE_INFO (decl)
+      && uses_template_parms (DECL_TI_ARGS (decl)))
+    return;
+
   DECL_ODR_USED (decl) = 1;
   if (DECL_CLONED_FUNCTION_P (decl))
     DECL_ODR_USED (DECL_CLONED_FUNCTION (decl)) = 1;
@@ -4233,8 +4290,6 @@  mark_used (tree decl)
        need.  Therefore, we always try to defer instantiation.  */
     instantiate_decl (decl, /*defer_ok=*/true,
 		      /*expl_inst_class_mem_p=*/false);
-
-  processing_template_decl = saved_processing_template_decl;
 }
 
 #include "gt-cp-decl2.h"
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8a6d451..0047aae 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16714,7 +16714,7 @@  always_instantiate_p (tree decl)
 	     their initializers are available in integral constant
 	     expressions.  */
 	  || (TREE_CODE (decl) == VAR_DECL
-	      && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)));
+	      && decl_maybe_constant_var_p (decl)));
 }
 
 /* Produce the definition of D, a _DECL generated from a template.  If
@@ -16750,7 +16750,8 @@  instantiate_decl (tree d, int defer_ok,
      case that an expression refers to the value of the variable --
      if the variable has a constant value the referring expression can
      take advantage of that fact.  */
-  if (TREE_CODE (d) == VAR_DECL)
+  if (TREE_CODE (d) == VAR_DECL
+      || DECL_DECLARED_CONSTEXPR_P (d))
     defer_ok = 0;
 
   /* Don't instantiate cloned functions.  Instead, instantiate the
@@ -16926,6 +16927,11 @@  instantiate_decl (tree d, int defer_ok,
 	permerror (input_location,  "explicit instantiation of %qD "
 		   "but no definition available", d);
 
+      /* If we're in unevaluated context, we just wanted to get the
+	 constant value; this isn't an odr use, so don't queue
+	 a full instantiation.  */
+      if (cp_unevaluated_operand != 0)
+	goto out;
       /* ??? Historically, we have instantiated inline functions, even
 	 when marked as "extern template".  */
       if (!(external_p && TREE_CODE (d) == VAR_DECL))
diff --git a/gcc/cp/repo.c b/gcc/cp/repo.c
index 22d58af..357dcd9 100644
--- a/gcc/cp/repo.c
+++ b/gcc/cp/repo.c
@@ -319,7 +319,7 @@  repo_emit_p (tree decl)
 	 available.  Still record them into *.rpo files, so if they
 	 weren't actually emitted and collect2 requests them, they can
 	 be provided.  */
-      if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+      if (decl_maybe_constant_var_p (decl)
 	  && DECL_CLASS_SCOPE_P (decl))
 	ret = 2;
     }
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5926963..ad26abb 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2826,7 +2826,7 @@  finish_id_expression (tree id_expression,
 	     the complexity of the problem"
 
 	     FIXME update for final resolution of core issue 696.  */
-	  if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
+	  if (decl_constant_var_p (decl))
 	    return integral_constant_value (decl);
 
 	  if (TYPE_P (context))
@@ -3077,21 +3077,6 @@  finish_id_expression (tree id_expression,
 	  return id_expression;
 	}
 
-      /* Only certain kinds of names are allowed in constant
-	 expression.  Enumerators and template parameters have already
-	 been handled above.  */
-      if (integral_constant_expression_p
-	  && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
-	  && ! builtin_valid_in_constant_expr_p (decl))
-	{
-	  if (!allow_non_integral_constant_expression_p)
-	    {
-	      error ("%qD cannot appear in a constant-expression", decl);
-	      return error_mark_node;
-	    }
-	  *non_integral_constant_expression_p = true;
-	}
-
       if (TREE_CODE (decl) == NAMESPACE_DECL)
 	{
 	  error ("use of namespace %qD as expression", decl);
@@ -3118,6 +3103,21 @@  finish_id_expression (tree id_expression,
 	  || TREE_CODE (decl) == RESULT_DECL)
 	mark_used (decl);
 
+      /* Only certain kinds of names are allowed in constant
+	 expression.  Enumerators and template parameters have already
+	 been handled above.  */
+      if (integral_constant_expression_p
+	  && ! decl_constant_var_p (decl)
+	  && ! builtin_valid_in_constant_expr_p (decl))
+	{
+	  if (!allow_non_integral_constant_expression_p)
+	    {
+	      error ("%qD cannot appear in a constant-expression", decl);
+	      return error_mark_node;
+	    }
+	  *non_integral_constant_expression_p = true;
+	}
+
       if (scope)
 	{
 	  decl = (adjust_result_of_qualified_name_lookup