Patchwork C++ PATCHes for c++/46977 (C++0x ICE on template with statement-expression)

login
register
mail settings
Submitter Jason Merrill
Date Jan. 21, 2011, 5:20 p.m.
Message ID <4D39C06E.9040401@redhat.com>
Download mbox | patch
Permalink /patch/79868/
State New
Headers show

Comments

Jason Merrill - Jan. 21, 2011, 5:20 p.m.
The crash here came because we were trying to fold_non_dependent_expr 
the statement-expression, which meant testing it for value-dependence, 
which crashed because value_dependent_expression_p doesn't know how to 
handle STMT_EXPR.

The simple fix (the first patch) is just to add STMT_EXPR to 
value_dependent_expression_p so we don't crash.  But this is really just 
papering over the underlying problem: we shouldn't be testing for 
value-dependence of non-constant-expressions, as value dependence is a 
property of constant expressions, not expressions in general.

The second patch, which I'm checking in, improves 
potential_constant_expression to be a predicate that we can use on 
template expressions in C++0x mode to determine whether or not the 
expression could possibly be a constant expression.  In C++98 mode it 
always returns true, as we filtered out unsuitable expressions earlier 
in the parser.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 44b8b455b98d1152c9f5362e52393f24e7e04841
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 14 18:30:41 2011 -0500

    	PR c++/46977
    	* pt.c (value_dependent_expression_p): Return true for STMT_EXPR.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2491047..21dce62 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,17 @@
 2011-01-17  Jason Merrill  <jason@redhat.com>
 
+	PR c++/46977
+	* semantics.c (potential_constant_expression_1): Split out from
+	potential_constant_expression.  Add want_rval parm.  Handle
+	template expression forms.  Don't enforce restriction on address
+	of automatic variable here.  Add a couple of diagnostics that
+	had been missing.
+	(require_potential_constant_expression): New entry point.
+	(build_data_member_initialization, register_constexpr_fundef): Adjust.
+	(maybe_constant_value): Check potential_constant_expression.
+	* pt.c (fold_non_dependent_expr_sfinae): Likewise.
+	* tree.c (build_vec_init_expr): Adjust.
+
 	PR c++/47067
 	* semantics.c (base_field_constructor_elt): New fn.
 	(cxx_eval_bare_aggregate): Use it.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3d39b55..7500826 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5245,7 +5245,8 @@ extern tree validate_constexpr_fundecl (tree);
 extern tree register_constexpr_fundef (tree, tree);
 extern bool check_constexpr_ctor_body (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
-extern bool potential_constant_expression (tree, tsubst_flags_t);
+extern bool potential_constant_expression (tree);
+extern bool require_potential_constant_expression (tree);
 extern tree cxx_constant_value (tree);
 extern tree maybe_constant_value (tree);
 extern tree maybe_constant_init (tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 16bd2a0..fb12382 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5159,6 +5159,7 @@ fold_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
      as two declarations of the same function, for example.  */
   if (processing_template_decl
       && !type_dependent_expression_p (expr)
+      && potential_constant_expression (expr)
       && !value_dependent_expression_p (expr))
     {
       HOST_WIDE_INT saved_processing_template_decl;
@@ -17964,11 +17965,11 @@ 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?
+/* Note that this predicate is not appropriate for general expressions;
+   only constant expressions (that satisfy potential_constant_expression)
+   can be tested for value dependence.
+
+   We should really also have a predicate for "instantiation-dependent".
 
    fold_non_dependent_expr: fold if constant and not type-dependent and not value-dependent.
      (what about instantiation-dependent constant-expressions?)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 285b764..fa35d4a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5532,7 +5532,7 @@ build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
 	  gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member))));
 	  /* But if the initializer isn't constexpr, leave it in so we
 	     complain later.  */
-	  if (potential_constant_expression (init, tf_none))
+	  if (potential_constant_expression (init))
 	    return true;
 	}
     }
@@ -5658,10 +5658,11 @@ register_constexpr_fundef (tree fun, tree body)
       body = unshare_expr (TREE_OPERAND (body, 0));
     }
 
-  if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun)
-					     ? tf_none : tf_error)))
+  if (!potential_constant_expression (body))
     {
       DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      if (!DECL_TEMPLATE_INSTANTIATION (fun))
+	require_potential_constant_expression (body);
       return NULL;
     }
   fundef->body = body;
@@ -7023,6 +7024,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
     case NON_DEPENDENT_EXPR:
     case BASELINK:
     case EXPR_STMT:
+    case OFFSET_REF:
       if (!allow_non_constant)
         error_at (EXPR_LOC_OR_HERE (t),
 		  "expression %qE is not a constant-expression", t);
@@ -7115,8 +7117,7 @@ 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.  */
+      || !potential_constant_expression (t)
       || value_dependent_expression_p (t))
     return t;
 
@@ -7148,6 +7149,8 @@ maybe_constant_init (tree t)
   return t;
 }
 
+#if 0
+/* FIXME see ADDR_EXPR section in potential_constant_expression_1.  */
 /* Return true if the object referred to by REF has automatic or thread
    local storage.  */
 
@@ -7170,6 +7173,7 @@ check_automatic_or_tls (tree ref)
   dk = decl_storage_duration (decl);
   return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok;
 }
+#endif
 
 /* Return true if the DECL designates a builtin function that is
    morally constexpr, in the sense that its parameter types and
@@ -7197,13 +7201,11 @@ morally_constexpr_builtin_function_p (tree decl)
   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.
+/* Return true if T denotes a potentially constant expression.  Issue
+   diagnostic as appropriate under control of FLAGS.  If WANT_RVAL is true,
+   an lvalue-rvalue conversion is implied.
 
-   C++0x [expr.const]
+   C++0x [expr.const] used to say
 
    6 An expression is a potential constant expression if it is
      a constant expression where all occurences of function
@@ -7216,13 +7218,23 @@ morally_constexpr_builtin_function_p (tree decl)
       logical OR (5.15), and conditional (5.16) operations that are
       not evaluated are not considered.   */
 
-bool
-potential_constant_expression (tree t, tsubst_flags_t flags)
+static bool
+potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 {
+  enum { any = false, rval = true };
   int i;
   tree tmp;
+
+  /* C++98 has different rules for the form of a constant expression that
+     are enforced in the parser, so we can assume that anything that gets
+     this far is suitable.  */
+  if (cxx_dialect < cxx0x)
+    return true;
+
   if (t == error_mark_node)
     return false;
+  if (t == NULL_TREE)
+    return true;
   if (TREE_THIS_VOLATILE (t))
     {
       if (flags & tf_error)
@@ -7235,8 +7247,18 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
   switch (TREE_CODE (t))
     {
     case FUNCTION_DECL:
+    case BASELINK:
+    case OVERLOAD:
+    case TEMPLATE_ID_EXPR:
     case LABEL_DECL:
     case CONST_DECL:
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+    case OFFSETOF_EXPR:
+    case NOEXCEPT_EXPR:
+    case TEMPLATE_PARM_INDEX:
+    case TRAIT_EXPR:
+    case IDENTIFIER_NODE:
       return true;
 
     case PARM_DECL:
@@ -7261,7 +7283,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
         const int nargs = call_expr_nargs (t);
         if (TREE_CODE (fun) != FUNCTION_DECL)
           {
-	    if (potential_constant_expression (fun, flags))
+	    if (potential_constant_expression_1 (fun, rval, flags))
 	      /* Might end up being a constant function pointer.  */
 	      return true;
             if (flags & tf_error)
@@ -7293,11 +7315,9 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             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))
+                else if (!potential_constant_expression_1 (x, rval, flags))
 		  {
 		    if (flags & tf_error)
 		      error ("object argument is not a potential constant "
@@ -7305,7 +7325,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
 		    return false;
 		  }
               }
-	    else if (!potential_constant_expression (x, flags))
+	    else if (!potential_constant_expression_1 (x, rval, flags))
 	      {
 		if (flags & tf_error)
 		  error ("argument in position %qP is not a "
@@ -7325,10 +7345,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             -- 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);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
 
     case VAR_DECL:
-      if (!decl_constant_var_p (t))
+      if (want_rval && !decl_constant_var_p (t))
         {
           if (flags & tf_error)
             error ("variable %qD is not declared constexpr", t);
@@ -7358,7 +7378,8 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                      "cannot yield a constant expression", from);
             return false;
           }
-        return potential_constant_expression (from, flags);
+        return (potential_constant_expression_1
+		(from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
       }
 
     case ADDR_EXPR:
@@ -7366,6 +7387,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             designates an object with thread or automatic storage
             duration;  */
       t = TREE_OPERAND (t, 0);
+#if 0
+      /* FIXME adjust when issue 1197 is fully resolved.  For now don't do
+         any checking here, as we might dereference the pointer later.  If
+         we remove this code, also remove check_automatic_or_tls.  */
       i = check_automatic_or_tls (t);
       if (i == ck_ok)
 	return true;
@@ -7376,15 +7401,23 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "automatic storage is not a constant expression", t);
           return false;
         }
-      return potential_constant_expression (t, flags);
+#endif
+      return potential_constant_expression_1 (t, any, flags);
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
+    case ARROW_EXPR:
+    case OFFSET_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);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+					      want_rval, flags);
+
+    case EXPR_PACK_EXPANSION:
+      return potential_constant_expression_1 (PACK_EXPANSION_PATTERN (t),
+					      want_rval, flags);
 
     case INDIRECT_REF:
       {
@@ -7392,7 +7425,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
         STRIP_NOPS (x);
         if (is_this_parameter (x))
 	  return true;
-	return potential_constant_expression (x, flags);
+	return potential_constant_expression_1 (x, rval, flags);
       }
 
     case LAMBDA_EXPR:
@@ -7417,6 +7450,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case MUST_NOT_THROW_EXPR:
     case TRY_CATCH_EXPR:
     case STATEMENT_LIST:
+      /* Don't bother trying to define a subset of statement-expressions to
+	 be constant-expressions, at least for now.  */
+    case STMT_EXPR:
+    case EXPR_STMT:
     case BIND_EXPR:
       if (flags & tf_error)
         error ("expression %qE is not a constant-expression", t);
@@ -7427,7 +7464,8 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             class type;  */
       {
         tree e = TREE_OPERAND (t, 0);
-        if (!TYPE_P (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+        if (!TYPE_P (e) && !type_dependent_expression_p (e)
+	    && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
           {
             if (flags & tf_error)
               error ("typeid-expression is not a constant expression "
@@ -7447,6 +7485,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "a constant expression");
           return false;
         }
+      want_rval = true;
       goto binary;
 
     case LT_EXPR:
@@ -7465,6 +7504,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "constant expression");
           return false;
         }
+      want_rval = true;
       goto binary;
 
     case REALPART_EXPR:
@@ -7477,22 +7517,41 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case ABS_EXPR:
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case UNARY_PLUS_EXPR:
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval,
+					      flags);
+
+    case CAST_EXPR:
+    case CONST_CAST_EXPR:
+    case STATIC_CAST_EXPR:
+    case REINTERPRET_CAST_EXPR:
+      return (potential_constant_expression_1
+	      (TREE_OPERAND (t, 0),
+	       TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
+
     case PAREN_EXPR:
-    case FIXED_CONVERT_EXPR:
+    case NON_DEPENDENT_EXPR:
       /* For convenience.  */
     case RETURN_EXPR:
-      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+					      want_rval, flags);
+
+    case SCOPE_REF:
+      return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+					      want_rval, flags);
 
     case INIT_EXPR:
     case TARGET_EXPR:
-      return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+					      rval, 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))
+	  if (!potential_constant_expression_1 (ce->value, want_rval, flags))
 	    return false;
 	return true;
       }
@@ -7501,11 +7560,13 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
       {
 	gcc_assert (TREE_PURPOSE (t) == NULL_TREE
 		    || DECL_P (TREE_PURPOSE (t)));
-	if (!potential_constant_expression (TREE_VALUE (t), flags))
+	if (!potential_constant_expression_1 (TREE_VALUE (t), want_rval,
+					      flags))
 	  return false;
 	if (TREE_CHAIN (t) == NULL_TREE)
 	  return true;
-	return potential_constant_expression (TREE_CHAIN (t), flags);
+	return potential_constant_expression_1 (TREE_CHAIN (t), want_rval,
+						flags);
       }
 
     case TRUNC_DIV_EXPR:
@@ -7515,10 +7576,24 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      if (integer_zerop (maybe_constant_value (TREE_OPERAND (t, 1))))
-	return false;
-      else
-	goto binary;
+      {
+	tree denom = TREE_OPERAND (t, 1);
+	/* We can't call maybe_constant_value on an expression
+	   that hasn't been through fold_non_dependent_expr yet.  */
+	if (!processing_template_decl)
+	  denom = maybe_constant_value (denom);
+	if (integer_zerop (denom))
+	  {
+	    if (flags & tf_error)
+	      error ("division by zero is not a constant-expression");
+	    return false;
+	  }
+	else
+	  {
+	    want_rval = true;
+	    goto binary;
+	  }
+      }
 
     case COMPOUND_EXPR:
       {
@@ -7530,7 +7605,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
 	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);
+	  return potential_constant_expression_1 (op0, want_rval, flags);
 	else
 	  goto binary;
       }
@@ -7547,37 +7622,41 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
       tmp = boolean_false_node;
     truth:
       if (TREE_OPERAND (t, 0) == tmp)
-	return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+	return potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags);
       else
-	return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+	return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
 
+    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:
+      want_rval = true;
+      /* Fall through.  */
     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:
+    case MEMBER_REF:
+    case DOTSTAR_EXPR:
     binary:
       for (i = 0; i < 2; ++i)
-	if (!potential_constant_expression (TREE_OPERAND (t, i),
-				      flags))
+	if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
+					      want_rval, flags))
 	  return false;
       return true;
 
@@ -7587,21 +7666,28 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
 	 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))
+      if (!potential_constant_expression_1 (tmp, rval, flags))
 	return false;
       else if (tmp == boolean_true_node)
-	return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+	return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+						want_rval, flags);
       else if (tmp == boolean_false_node)
-	return potential_constant_expression (TREE_OPERAND (t, 2), flags);
+	return potential_constant_expression_1 (TREE_OPERAND (t, 2),
+						want_rval, flags);
       for (i = 1; i < 3; ++i)
-	if (potential_constant_expression (TREE_OPERAND (t, i), tf_none))
+	if (potential_constant_expression_1 (TREE_OPERAND (t, i),
+					     want_rval, tf_none))
 	  return true;
       if (flags & tf_error)
         error ("expression %qE is not a constant-expression", t);
       return false;
 
     case VEC_INIT_EXPR:
-      return VEC_INIT_EXPR_IS_CONSTEXPR (t);
+      if (VEC_INIT_EXPR_IS_CONSTEXPR (t))
+	return true;
+      if (flags & tf_error)
+        error ("non-constant array initialization");
+      return false;
 
     default:
       sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
@@ -7610,6 +7696,21 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     }
 }
 
+/* The main entry point to the above.  */
+
+bool
+potential_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, tf_none);
+}
+
+/* Like above, but complain about non-constant expressions.  */
+
+bool
+require_potential_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, tf_warning_or_error);
+}
 
 /* Constructor for a lambda expression.  */
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 813b88d..1a1f150 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -513,9 +513,13 @@ build_vec_init_expr (tree type, tree init)
   SET_EXPR_LOCATION (init, input_location);
 
   if (current_function_decl
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
-      && potential_constant_expression (elt_init, tf_warning_or_error))
-    VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+    {
+      if (potential_constant_expression (elt_init))
+	VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
+      else if (!processing_template_decl)
+	require_potential_constant_expression (elt_init);
+    }
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
   init = build_target_expr (slot, init);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e12ba4c..29d316c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
 2011-01-17  Jason Merrill  <jason@redhat.com>
 
+	* g++.dg/cpp0x/constexpr-stmtexpr.C: New.
+
 	* g++.dg/cpp0x/constexpr-virtual.C: New.
 
 2011-01-17  Jakub Jelinek  <jakub@redhat.com>
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C
new file mode 100644
index 0000000..40e0c2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C
@@ -0,0 +1,8 @@
+// PR c++/46977
+// { dg-options "-std=c++0x" }
+
+template < typename > void
+foo ()
+{
+  ({int i;}), 0;
+}
H.J. Lu - Jan. 28, 2011, 7:01 p.m.
On Fri, Jan 21, 2011 at 9:20 AM, Jason Merrill <jason@redhat.com> wrote:
> The crash here came because we were trying to fold_non_dependent_expr the
> statement-expression, which meant testing it for value-dependence, which
> crashed because value_dependent_expression_p doesn't know how to handle
> STMT_EXPR.
>
> The second patch, which I'm checking in, improves
> potential_constant_expression to be a predicate that we can use on template
> expressions in C++0x mode to determine whether or not the expression could
> possibly be a constant expression.  In C++98 mode it always returns true, as
> we filtered out unsuitable expressions earlier in the parser.
>
> Tested x86_64-pc-linux-gnu, applied to trunk.
>

> diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> index 2491047..21dce62 100644
> --- a/gcc/cp/ChangeLog
> +++ b/gcc/cp/ChangeLog
> @@ -1,5 +1,17 @@
>  2011-01-17  Jason Merrill  <jason@redhat.com>
>
> +       PR c++/46977
> +       * semantics.c (potential_constant_expression_1): Split out from
> +       potential_constant_expression.  Add want_rval parm.  Handle
> +       template expression forms.  Don't enforce restriction on address
> +       of automatic variable here.  Add a couple of diagnostics that
> +       had been missing.
> +       (require_potential_constant_expression): New entry point.
> +       (build_data_member_initialization, register_constexpr_fundef):
> Adjust.
> +       (maybe_constant_value): Check potential_constant_expression.
> +       * pt.c (fold_non_dependent_expr_sfinae): Likewise.
> +       * tree.c (build_vec_init_expr): Adjust.
> +

This patch caused:

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

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 16bd2a0..32b2520 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18142,6 +18142,11 @@  value_dependent_expression_p (tree expression)
 	return false;
       }
 
+    case STMT_EXPR:
+      /* Return true for a statement-expression.  FIXME this isn't
+	 value-dependent, it's non-constant.  */
+      return true;
+
     default:
       /* A constant expression is value-dependent if any subexpression is
 	 value-dependent.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C
new file mode 100644
index 0000000..40e0c2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C
@@ -0,0 +1,8 @@ 
+// PR c++/46977
+// { dg-options "-std=c++0x" }
+
+template < typename > void
+foo ()
+{
+  ({int i;}), 0;
+}