This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA (tree-inline): PATCH for more C++14 constexpr support


On 11/15/2014 11:59 PM, Jason Merrill wrote:
This handles some more C++14 testcases and has no regressions on C++11
constexpr testcases.  Support for jumps will follow soon.

Like this, though it still needs a bit of cleaning up.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 53cfb18..611d4f2 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -871,7 +871,7 @@ struct constexpr_ctx {
 static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
 
 static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
-					  bool, bool, bool *, bool *);
+					  bool, bool, bool *, bool *, tree *);
 
 /* Compute a hash value for a constexpr call representation.  */
 
@@ -993,7 +993,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
     {
       args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i),
 					      allow_non_constant, addr,
-					      non_constant_p, overflow_p);
+					      non_constant_p, overflow_p,
+					      NULL);
       if (allow_non_constant && *non_constant_p)
 	return t;
     }
@@ -1070,7 +1071,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 	}
       arg = cxx_eval_constant_expression (ctx, x, allow_non_constant,
 					  TREE_CODE (type) == REFERENCE_TYPE,
-					  non_constant_p, overflow_p);
+					  non_constant_p, overflow_p, NULL);
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p && allow_non_constant)
 	return;
@@ -1151,7 +1152,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       /* Might be a constexpr function pointer.  */
       fun = cxx_eval_constant_expression (ctx, fun, allow_non_constant,
 					  /*addr*/false, non_constant_p,
-					  overflow_p);
+					  overflow_p, NULL);
       STRIP_NOPS (fun);
       if (TREE_CODE (fun) == ADDR_EXPR)
 	fun = TREE_OPERAND (fun, 0);
@@ -1187,7 +1188,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	{
 	  tree arg = convert_from_reference (get_nth_callarg (t, 1));
 	  return cxx_eval_constant_expression (ctx, arg, allow_non_constant,
-					       addr, non_constant_p, overflow_p);
+					       addr, non_constant_p,
+					       overflow_p, NULL);
 	}
       else if (TREE_CODE (t) == AGGR_INIT_EXPR
 	       && AGGR_INIT_ZERO_FIRST (t))
@@ -1270,7 +1272,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	      result = (cxx_eval_constant_expression
 			(&new_ctx, new_call.fundef->body,
 			 allow_non_constant, addr,
-			 non_constant_p, overflow_p));
+			 non_constant_p, overflow_p, NULL));
 	    }
 	  else
 	    {
@@ -1310,8 +1312,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	      else
 		ctx->values->put (res, NULL_TREE);
 
+	      tree jump_target = NULL_TREE;
 	      cxx_eval_constant_expression (ctx, body, allow_non_constant,
-					    addr, non_constant_p, overflow_p);
+					    addr, non_constant_p, overflow_p,
+					    &jump_target);
 
 	      if (VOID_TYPE_P (TREE_TYPE (res)))
 		/* This can be null for a subobject constructor call, in
@@ -1320,7 +1324,16 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 		   to put such a call in the hash table.  */
 		result = addr ? ctx->object : ctx->ctor;
 	      else
-		result = *ctx->values->get (slot ? slot : res);
+		{
+		  result = *ctx->values->get (slot ? slot : res);
+		  if (result == NULL_TREE)
+		    {
+		      if (!allow_non_constant)
+			error ("constexpr call flows off the end "
+			       "of the function");
+		      *non_constant_p = true;
+		    }
+		}
 
 	      /* Remove the parms/result from the values map.  Is it worth
 		 bothering to do this when the map itself is only live for
@@ -1433,7 +1446,8 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
   tree r;
   tree orig_arg = TREE_OPERAND (t, 0);
   tree arg = cxx_eval_constant_expression (ctx, orig_arg, allow_non_constant,
-					   addr, non_constant_p, overflow_p);
+					   addr, non_constant_p, overflow_p,
+					   NULL);
   VERIFY_CONSTANT (arg);
   if (arg == orig_arg)
     return t;
@@ -1456,11 +1470,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
   tree lhs, rhs;
   lhs = cxx_eval_constant_expression (ctx, orig_lhs,
 				      allow_non_constant, addr,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, NULL);
   VERIFY_CONSTANT (lhs);
   rhs = cxx_eval_constant_expression (ctx, orig_rhs,
 				      allow_non_constant, addr,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, NULL);
   VERIFY_CONSTANT (rhs);
   if (lhs == orig_lhs && rhs == orig_rhs)
     return t;
@@ -1476,20 +1490,24 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 static tree
 cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
 				 bool allow_non_constant, bool addr,
-				 bool *non_constant_p, bool *overflow_p)
+				 bool *non_constant_p, bool *overflow_p,
+				 tree *jump_target)
 {
   tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
 					   allow_non_constant, addr,
-					   non_constant_p, overflow_p);
+					   non_constant_p, overflow_p,
+					   NULL);
   VERIFY_CONSTANT (val);
   /* Don't VERIFY_CONSTANT the other operands.  */
   if (integer_zerop (val))
     return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
 					 allow_non_constant, addr,
-					 non_constant_p, overflow_p);
+					 non_constant_p, overflow_p,
+					 jump_target);
   return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 				       allow_non_constant, addr,
-				       non_constant_p, overflow_p);
+				       non_constant_p, overflow_p,
+				       jump_target);
 }
 
 /* Subroutine of cxx_eval_constant_expression.
@@ -1503,7 +1521,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
   tree oldary = TREE_OPERAND (t, 0);
   tree ary = cxx_eval_constant_expression (ctx, oldary,
 					   allow_non_constant, addr,
-					   non_constant_p, overflow_p);
+					   non_constant_p, overflow_p, NULL);
   tree index, oldidx;
   HOST_WIDE_INT i;
   tree elem_type;
@@ -1513,7 +1531,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
   oldidx = TREE_OPERAND (t, 1);
   index = cxx_eval_constant_expression (ctx, oldidx,
 					allow_non_constant, false,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p, NULL);
   VERIFY_CONSTANT (index);
   if (addr && ary == oldary && index == oldidx)
     return t;
@@ -1545,7 +1563,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 	  val = build_cplus_new (elem_type, val, tf_warning_or_error);
 	  return cxx_eval_constant_expression (ctx, val,
 					       allow_non_constant, addr,
-					       non_constant_p, overflow_p);
+					       non_constant_p, overflow_p,
+					       NULL);
 	}
 
       if (!allow_non_constant)
@@ -1591,7 +1610,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree orig_whole = TREE_OPERAND (t, 0);
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     allow_non_constant, addr,
-					     non_constant_p, overflow_p);
+					     non_constant_p, overflow_p, NULL);
   if (whole == orig_whole)
     return t;
   if (addr)
@@ -1651,7 +1670,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   value = build_cplus_new (TREE_TYPE (t), value, tf_warning_or_error);
   return cxx_eval_constant_expression (ctx, value,
 				       allow_non_constant, addr,
-				       non_constant_p, overflow_p);
+				       non_constant_p, overflow_p, NULL);
 }
 
 /* Subroutine of cxx_eval_constant_expression.
@@ -1669,7 +1688,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
   HOST_WIDE_INT istart, isize;
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     allow_non_constant, addr,
-					     non_constant_p, overflow_p);
+					     non_constant_p, overflow_p, NULL);
   tree start, field, value;
   unsigned HOST_WIDE_INT i;
 
@@ -1752,13 +1771,14 @@ cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
   tree r;
   tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
 					   allow_non_constant, addr,
-					   non_constant_p, overflow_p);
+					   non_constant_p, overflow_p, NULL);
   VERIFY_CONSTANT (lhs);
   if (tree_int_cst_equal (lhs, bailout_value))
     return lhs;
   gcc_assert (tree_int_cst_equal (lhs, continue_value));
   r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-				    allow_non_constant, addr, non_constant_p, overflow_p);
+				    allow_non_constant, addr, non_constant_p,
+				    overflow_p, NULL);
   VERIFY_CONSTANT (r);
   return r;
 }
@@ -1901,7 +1921,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
 	CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
       tree elt = cxx_eval_constant_expression (&new_ctx, value,
 					       allow_non_constant, addr,
-					       non_constant_p, overflow_p);
+					       non_constant_p, overflow_p,
+					       NULL);
       /* Don't VERIFY_CONSTANT here.  */
       if (allow_non_constant && *non_constant_p)
 	break;
@@ -2018,7 +2039,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 	     we just pre-built above.  */
 	  eltinit = (cxx_eval_constant_expression
 		     (&new_ctx, init, allow_non_constant,
-		      addr, non_constant_p, overflow_p));
+		      addr, non_constant_p, overflow_p, NULL));
 	}
       else
 	{
@@ -2032,7 +2053,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 	  eltinit = force_rvalue (eltinit, tf_warning_or_error);
 	  eltinit = (cxx_eval_constant_expression
 		     (&new_ctx, eltinit, allow_non_constant, addr,
-		      non_constant_p, overflow_p));
+		      non_constant_p, overflow_p, NULL));
 	}
       if (*non_constant_p && !allow_non_constant)
 	break;
@@ -2268,7 +2289,8 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 {
   tree orig_op0 = TREE_OPERAND (t, 0);
   tree op0 = cxx_eval_constant_expression (ctx, orig_op0, allow_non_constant,
-					   /*addr*/false, non_constant_p, overflow_p);
+					   /*addr*/false, non_constant_p,
+					   overflow_p, NULL);
   bool empty_base = false;
   tree r;
 
@@ -2281,7 +2303,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 
   if (r)
     r = cxx_eval_constant_expression (ctx, r, allow_non_constant,
-				      addr, non_constant_p, overflow_p);
+				      addr, non_constant_p, overflow_p, NULL);
   else
     {
       tree sub = op0;
@@ -2383,7 +2405,8 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
     {
       args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
 					      allow_non_constant, addr,
-					      non_constant_p, overflow_p);
+					      non_constant_p, overflow_p,
+					      NULL);
       VERIFY_CONSTANT (args[i]);
     }
 
@@ -2416,7 +2439,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
   tree target = TREE_OPERAND (t, 0);
   target = cxx_eval_constant_expression (ctx, target,
 					 allow_non_constant, true,
-					 non_constant_p, overflow_p);
+					 non_constant_p, overflow_p, NULL);
   if (*non_constant_p)
     return t;
   new_ctx.object = target;
@@ -2497,7 +2520,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 
   tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1),
 					    allow_non_constant, false,
-					    non_constant_p, overflow_p);
+					    non_constant_p, overflow_p, NULL);
   if (target == object)
     /* The hash table might have moved since the get earlier.  */
     ctx->values->put (object, init);
@@ -2527,12 +2550,12 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
 
   /* The operand as an lvalue.  */
   op = cxx_eval_constant_expression (ctx, op, allow_non_constant, true,
-				     non_constant_p, overflow_p);
+				     non_constant_p, overflow_p, NULL);
 
   /* The operand as an rvalue.  */
   tree val = rvalue (op);
   val = cxx_eval_constant_expression (ctx, val, allow_non_constant, false,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, NULL);
   VERIFY_CONSTANT (val);
 
   /* The modified value.  */
@@ -2544,7 +2567,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
   /* Storing the modified value.  */
   tree store = build2 (MODIFY_EXPR, type, op, mod);
   cxx_eval_constant_expression (ctx, store, allow_non_constant,
-				true, non_constant_p, overflow_p);
+				true, non_constant_p, overflow_p, NULL);
 
   /* And the value of the expression.  */
   if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
@@ -2561,6 +2584,146 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
     return val;
 }
 
+static bool
+jump_returns (tree *jump_target)
+{
+  return *jump_target
+    && TREE_CODE (*jump_target) == RETURN_EXPR;
+}
+
+static bool
+jump_breaks (tree *jump_target)
+{
+  return *jump_target
+    && TREE_CODE (*jump_target) == LABEL_DECL
+    && LABEL_DECL_BREAK (*jump_target);
+}
+
+#if 0
+static bool
+jump_continues (tree *jump_target)
+{
+  return *jump_target
+    && TREE_CODE (*jump_target) == LABEL_DECL
+    && LABEL_DECL_CONTINUE (*jump_target);
+}
+#endif
+
+static bool
+jump_case (tree *jump_target)
+{
+  return *jump_target
+    && TREE_CODE (*jump_target) == INTEGER_CST;
+}
+
+static bool
+label_matches (tree *jump_target, tree_stmt_iterator i,
+	       tree_stmt_iterator& default_label)
+{
+  tree stmt = tsi_stmt (i);
+  switch (TREE_CODE (*jump_target))
+    {
+    case LABEL_DECL:
+      if (TREE_CODE (stmt) == LABEL_EXPR
+	  && LABEL_EXPR_LABEL (stmt) == *jump_target)
+	return true;
+      break;
+
+    case INTEGER_CST:
+      if (TREE_CODE (stmt) == CASE_LABEL_EXPR)
+	{
+	  if (!CASE_LOW (stmt))
+	    default_label = i;
+	  else if (tree_int_cst_equal (*jump_target, CASE_LOW (stmt)))
+	    return true;
+	}
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+  return false;
+}
+
+static tree
+cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
+			 bool allow_non_constant,
+			 bool *non_constant_p, bool *overflow_p,
+			 tree *jump_target)
+{
+  tree_stmt_iterator i;
+  tree_stmt_iterator default_label = tree_stmt_iterator();
+  for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+    {
+    reenter:
+      tree stmt = tsi_stmt (i);
+      if (*jump_target)
+	{
+	  if (TREE_CODE (stmt) == STATEMENT_LIST)
+	    /* The label we want might be inside.  */;
+	  else if (label_matches (jump_target, i, default_label))
+	    /* Found it.  */
+	    *jump_target = NULL_TREE;
+	  else
+	    continue;
+	}
+      cxx_eval_constant_expression (ctx, stmt,
+				    allow_non_constant, false,
+				    non_constant_p, overflow_p,
+				    jump_target);
+      if (*non_constant_p)
+	break;
+      if (jump_returns (jump_target) || jump_breaks (jump_target))
+	break;
+    }
+  if (jump_case (jump_target) && !tsi_end_p (default_label))
+    {
+      i = default_label;
+      *jump_target = NULL_TREE;
+      goto reenter;
+    }
+  return NULL_TREE;
+}
+
+static tree
+cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
+		    bool allow_non_constant,
+		    bool *non_constant_p, bool *overflow_p,
+		    tree *jump_target)
+{
+  tree body = TREE_OPERAND (t, 0);
+  while (true)
+    {
+      cxx_eval_statement_list (ctx, body, allow_non_constant,
+			       non_constant_p, overflow_p, jump_target);
+      if (jump_returns (jump_target) || jump_breaks (jump_target))
+	break;
+    }
+  if (jump_breaks (jump_target))
+    *jump_target = NULL_TREE;
+  return NULL_TREE;
+}
+
+static tree
+cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
+		      bool allow_non_constant,
+		      bool *non_constant_p, bool *overflow_p,
+		      tree *jump_target)
+{
+  tree cond = TREE_OPERAND (t, 0);
+  cond = cxx_eval_constant_expression (ctx, cond, allow_non_constant, false,
+				       non_constant_p, overflow_p, NULL);
+  VERIFY_CONSTANT (cond);
+  *jump_target = cond;
+
+  tree body = TREE_OPERAND (t, 1);
+  cxx_eval_statement_list (ctx, body, allow_non_constant,
+			   non_constant_p, overflow_p, jump_target);
+  if (jump_breaks (jump_target) || jump_case (jump_target))
+    *jump_target = NULL_TREE;
+  return NULL_TREE;
+}
+
 /* 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 */
@@ -2568,7 +2731,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
 static tree
 cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 			      bool allow_non_constant, bool addr,
-			      bool *non_constant_p, bool *overflow_p)
+			      bool *non_constant_p, bool *overflow_p,
+			      tree *jump_target)
 {
   constexpr_ctx new_ctx;
   tree r = t;
@@ -2623,6 +2787,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case FUNCTION_DECL:
     case TEMPLATE_DECL:
     case LABEL_DECL:
+    case LABEL_EXPR:
+    case CASE_LABEL_EXPR:
       return t;
 
     case PARM_DECL:
@@ -2667,7 +2833,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  {
 	    init = cxx_eval_constant_expression (ctx, init,
 						 allow_non_constant, false,
-						 non_constant_p, overflow_p);
+						 non_constant_p, overflow_p,
+						 NULL);
 	    ctx->values->put (r, init);
 	  }
 	else if (ctx == &new_ctx)
@@ -2705,7 +2872,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	 initialization of a temporary.  */
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					allow_non_constant, false,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p, NULL);
       if (!*non_constant_p)
 	/* Adjust the type of the result to the type of the temporary.  */
 	r = adjust_temp_type (TREE_TYPE (t), r);
@@ -2718,7 +2885,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	     not the side-effect of the initialization.  */
 	  r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					    allow_non_constant, false,
-					    non_constant_p, overflow_p);
+					    non_constant_p, overflow_p, NULL);
 	  break;
 	}
       /* else fall through */
@@ -2730,10 +2897,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case SCOPE_REF:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					allow_non_constant, addr,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p, NULL);
       break;
 
     case RETURN_EXPR:
+      r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+					allow_non_constant, addr,
+					non_constant_p, overflow_p,
+					jump_target);
+      *jump_target = t;
+      break;
+
     case NON_LVALUE_EXPR:
     case TRY_CATCH_EXPR:
     case CLEANUP_POINT_EXPR:
@@ -2743,7 +2917,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case EH_SPEC_BLOCK:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
 					allow_non_constant, addr,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p,
+					jump_target);
       break;
 
       /* These differ from cxx_eval_unary_expression in that this doesn't
@@ -2760,7 +2935,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						allow_non_constant,
 						/*addr*/true,
-						non_constant_p, overflow_p);
+						non_constant_p, overflow_p,
+						NULL);
 	/* Don't VERIFY_CONSTANT here.  */
 	if (*non_constant_p)
 	  return t;
@@ -2811,15 +2987,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
 	    || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
 	  r = cxx_eval_constant_expression (ctx, op0, allow_non_constant,
-					    addr, non_constant_p, overflow_p);
+					    addr, non_constant_p, overflow_p,
+					    jump_target);
 	else
 	  {
 	    /* Check that the LHS is constant and then discard it.  */
 	    cxx_eval_constant_expression (ctx, op0, allow_non_constant,
-					  false, non_constant_p, overflow_p);
+					  false, non_constant_p, overflow_p,
+					  jump_target);
 	    op1 = TREE_OPERAND (t, 1);
 	    r = cxx_eval_constant_expression (ctx, op1, allow_non_constant,
-					      addr, non_constant_p, overflow_p);
+					      addr, non_constant_p, overflow_p,
+					      jump_target);
 	  }
       }
       break;
@@ -2913,7 +3092,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case COND_EXPR:
     case VEC_COND_EXPR:
       r = cxx_eval_conditional_expression (ctx, t, allow_non_constant, addr,
-					   non_constant_p, overflow_p);
+					   non_constant_p, overflow_p,
+					   jump_target);
       break;
 
     case CONSTRUCTOR:
@@ -2944,7 +3124,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	tree oldop = TREE_OPERAND (t, 0);
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						allow_non_constant, addr,
-						non_constant_p, overflow_p);
+						non_constant_p, overflow_p,
+						NULL);
 	if (*non_constant_p)
 	  return t;
 	if (POINTER_TYPE_P (TREE_TYPE (t))
@@ -2976,25 +3157,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
 
     case STATEMENT_LIST:
-      {
-	new_ctx = *ctx;
-	new_ctx.ctor = new_ctx.object = NULL_TREE;
-	tree_stmt_iterator i;
-	for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
-	  {
-	    cxx_eval_constant_expression (&new_ctx, tsi_stmt (i),
-					  allow_non_constant, false,
-					  non_constant_p, overflow_p);
-	    if (*non_constant_p)
-	      break;
-	  }
-      }
-      break;
+      new_ctx = *ctx;
+      new_ctx.ctor = new_ctx.object = NULL_TREE;
+      return cxx_eval_statement_list (&new_ctx, t, allow_non_constant,
+				      non_constant_p, overflow_p, jump_target);
 
     case BIND_EXPR:
       return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
 					   allow_non_constant, addr,
-					   non_constant_p, overflow_p);
+					   non_constant_p, overflow_p,
+					   jump_target);
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -3042,16 +3214,23 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  gcc_assert (same_type_ignoring_top_level_qualifiers_p
 		      (TREE_TYPE (t), TREE_TYPE (ctor)));
 	  return cxx_eval_constant_expression
-	    (ctx, ctor, allow_non_constant, addr, non_constant_p, overflow_p);
+	    (ctx, ctor, allow_non_constant, addr,
+	     non_constant_p, overflow_p, NULL);
 	}
       break;
 
     case GOTO_EXPR:
+      *jump_target = TREE_OPERAND (t, 0);
+      break;
+
     case LOOP_EXPR:
+      cxx_eval_loop_expr (ctx, t, allow_non_constant,
+			  non_constant_p, overflow_p, jump_target);
+      break;
+
     case SWITCH_EXPR:
-      if (!allow_non_constant)
-	sorry ("%qs in constant expression", get_tree_code_name (TREE_CODE (t)));
-      *non_constant_p = true;
+      cxx_eval_switch_expr (ctx, t, allow_non_constant,
+			    non_constant_p, overflow_p, jump_target);
       break;
 
     default:
@@ -3112,7 +3291,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
     }
 
   r = cxx_eval_constant_expression (&ctx, r, allow_non_constant,
-				    false, &non_constant_p, &overflow_p);
+				    false, &non_constant_p, &overflow_p, NULL);
 
   verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
 
@@ -3196,7 +3375,7 @@ is_sub_constant_expr (tree t)
       CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true;
     }
   cxx_eval_constant_expression (&ctx, t, true, false, &non_constant_p,
-				&overflow_p);
+				&overflow_p, NULL);
   return !non_constant_p && !overflow_p;
 }
 
@@ -3425,6 +3604,8 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case USING_DECL:
     case USING_STMT:
     case PLACEHOLDER_EXPR:
+    case BREAK_STMT:
+    case CONTINUE_STMT:
       return true;
 
     case AGGR_INIT_EXPR:
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 81b26d2..82be90b 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -74,6 +74,10 @@ begin_bc_block (enum bc_t bc, location_t location)
   tree label = create_artificial_label (location);
   DECL_CHAIN (label) = bc_label[bc];
   bc_label[bc] = label;
+  if (bc == bc_break)
+    LABEL_DECL_BREAK (label) = true;
+  else
+    LABEL_DECL_CONTINUE (label) = true;
   return label;
 }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 31e1620..e784589 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -148,12 +148,14 @@ c-common.h, not after.
       DECL_LOCAL_FUNCTION_P (in FUNCTION_DECL)
       DECL_MUTABLE_P (in FIELD_DECL)
       DECL_DEPENDENT_P (in USING_DECL)
+      LABEL_DECL_BREAK (in LABEL_DECL)
    1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
       DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
       DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
       USING_DECL_TYPENAME_P (in USING_DECL)
       DECL_VLA_CAPTURE_P (in FIELD_DECL)
       DECL_ARRAY_PARAMETER_P (in PARM_DECL)
+      LABEL_DECL_CONTINUE (in LABEL_DECL)
    2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
       DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
    3: DECL_IN_AGGR_P.
@@ -3243,6 +3245,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define DECL_LOCAL_FUNCTION_P(NODE) \
   DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))
 
+/* Nonzero if NODE is the target for genericization of 'break' stmts.  */
+#define LABEL_DECL_BREAK(NODE) \
+  DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE))
+
+/* Nonzero if NODE is the target for genericization of 'continue' stmts.  */
+#define LABEL_DECL_CONTINUE(NODE) \
+  DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE))
+
 /* True if NODE was declared with auto in its return type, but it has
    started compilation and so the return type might have been changed by
    return type deduction; its declared return type should be found in
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop1.C
new file mode 100644
index 0000000..fc5d4f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop1.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  int j = 0;
+  for (; i > 0; --i)
+    ++j;
+  return j;
+}
+
+constexpr int i = f(42);
+#define SA(X) static_assert((X),#X)
+SA(i==42);
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-return1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-return1.C
new file mode 100644
index 0000000..b114e21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-return1.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  return 24;
+  return 36;
+}
+
+constexpr int i = f(42);
+#define SA(X) static_assert((X),#X)
+SA(i==24);
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C
new file mode 100644
index 0000000..ae2628d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-return2.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+}
+
+constexpr int i = f(42);	// { dg-error "flows off the end" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-switch1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch1.C
new file mode 100644
index 0000000..add7323
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch1.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  switch (i)
+    {
+    case 1:
+      return 42;
+    default:
+      return 0;
+    }
+}
+
+constexpr int i = f(1);
+#define SA(X) static_assert((X),#X)
+SA(i==42);
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-switch2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch2.C
new file mode 100644
index 0000000..a459a5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch2.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  int j = 0;
+  switch (i)
+    {
+    case 1:
+      j = 42;
+      break;
+    default:
+      j = 24;
+      break;
+    }
+  return j;
+}
+
+constexpr int i = f(1);
+#define SA(X) static_assert((X),#X)
+SA(i==42);
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-switch3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch3.C
new file mode 100644
index 0000000..1aa1cf6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-switch3.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  int j = 0;
+  switch (i)
+    {
+    case 1:
+      j = 42;
+      break;
+    default:
+      j = 24;
+      break;
+    }
+  return j;
+}
+
+constexpr int i = f(2);
+#define SA(X) static_assert((X),#X)
+SA(i==24);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]