public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] rust-constexpr.cc: add more cases to eval_constant_expression()
@ 2022-08-29 15:33 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f21f475feca30d0c9fb74dfe3bb65a6d88d5311c

commit f21f475feca30d0c9fb74dfe3bb65a6d88d5311c
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Thu Jul 28 18:54:48 2022 +0100

    rust-constexpr.cc: add more cases to eval_constant_expression()
    
    Following cases have been added in this changeset:
     - LOOP_EXPR
     - WHILE_STMT
     - FOR_STMT
    
    These need following supporting functions which are also ported:
     - eval_loop_expr
     - returns
     - breaks
     - continues
     - switches

Diff:
---
 gcc/rust/backend/rust-constexpr.cc | 154 +++++++++++++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h       |  24 ++++++
 2 files changed, 178 insertions(+)

diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 9449d599884..cac28d6870f 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -493,6 +493,10 @@ static tree
 eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval,
 		    bool *non_constant_p, bool *overflow_p);
 
+static tree
+eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
+		bool *overflow_p, tree *jump_target);
+
 /* Variables and functions to manage constexpr call expansion context.
    These do not need to be marked for PCH or GC.  */
 
@@ -731,6 +735,12 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
 	}
       break;
 
+    case LOOP_EXPR:
+    case WHILE_STMT:
+    case FOR_STMT:
+      eval_loop_expr (ctx, t, non_constant_p, overflow_p, jump_target);
+      break;
+
     case BIT_FIELD_REF:
       r = eval_bit_field_ref (ctx, t, lval, non_constant_p, overflow_p);
       break;
@@ -774,6 +784,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
       r = eval_conditional_expression (ctx, t, lval, non_constant_p, overflow_p,
 				       jump_target);
       break;
+
     default:
       break;
     }
@@ -2760,6 +2771,149 @@ eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval,
   return error_mark_node;
 }
 
+/* Predicates for the meaning of *jump_target.  */
+
+static bool
+returns (tree *jump_target)
+{
+  return *jump_target
+	 && (TREE_CODE (*jump_target) == RETURN_EXPR
+	     || (TREE_CODE (*jump_target) == LABEL_DECL
+		 && LABEL_DECL_CDTOR (*jump_target)));
+}
+
+static bool
+breaks (tree *jump_target)
+{
+  return *jump_target
+	 && ((TREE_CODE (*jump_target) == LABEL_DECL
+	      && LABEL_DECL_BREAK (*jump_target))
+	     || TREE_CODE (*jump_target) == BREAK_STMT
+	     || TREE_CODE (*jump_target) == EXIT_EXPR);
+}
+
+static bool
+continues (tree *jump_target)
+{
+  return *jump_target
+	 && ((TREE_CODE (*jump_target) == LABEL_DECL
+	      && LABEL_DECL_CONTINUE (*jump_target))
+	     || TREE_CODE (*jump_target) == CONTINUE_STMT);
+}
+
+static bool
+switches (tree *jump_target)
+{
+  return *jump_target && TREE_CODE (*jump_target) == INTEGER_CST;
+}
+
+/* Evaluate a LOOP_EXPR for side-effects.  Handles break and return
+   semantics; continue semantics are covered by cxx_eval_statement_list.  */
+
+static tree
+eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
+		bool *overflow_p, tree *jump_target)
+{
+  constexpr_ctx new_ctx = *ctx;
+  tree local_target;
+  if (!jump_target)
+    {
+      local_target = NULL_TREE;
+      jump_target = &local_target;
+    }
+
+  tree body, cond = NULL_TREE, expr = NULL_TREE;
+  int count = 0;
+  switch (TREE_CODE (t))
+    {
+    case LOOP_EXPR:
+      body = LOOP_EXPR_BODY (t);
+      break;
+    case WHILE_STMT:
+      body = WHILE_BODY (t);
+      cond = WHILE_COND (t);
+      count = -1;
+      break;
+    case FOR_STMT:
+      if (FOR_INIT_STMT (t))
+	eval_constant_expression (ctx, FOR_INIT_STMT (t), /*lval*/ false,
+				  non_constant_p, overflow_p, jump_target);
+      if (*non_constant_p)
+	return NULL_TREE;
+      body = FOR_BODY (t);
+      cond = FOR_COND (t);
+      expr = FOR_EXPR (t);
+      count = -1;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  auto_vec<tree, 10> save_exprs;
+  new_ctx.save_exprs = &save_exprs;
+  do
+    {
+      if (count != -1)
+	{
+	  if (body)
+	    eval_constant_expression (&new_ctx, body, /*lval*/ false,
+				      non_constant_p, overflow_p, jump_target);
+	  if (breaks (jump_target))
+	    {
+	      *jump_target = NULL_TREE;
+	      break;
+	    }
+
+	  if (TREE_CODE (t) != LOOP_EXPR && continues (jump_target))
+	    *jump_target = NULL_TREE;
+
+	  if (expr)
+	    eval_constant_expression (&new_ctx, expr, /*lval*/ false,
+				      non_constant_p, overflow_p, jump_target);
+	}
+
+      if (cond)
+	{
+	  tree res = eval_constant_expression (&new_ctx, cond, /*lval*/ false,
+					       non_constant_p, overflow_p,
+					       jump_target);
+	  if (res)
+	    {
+	      if (verify_constant (res, ctx->quiet, non_constant_p, overflow_p))
+		break;
+	      if (integer_zerop (res))
+		break;
+	    }
+	  else
+	    gcc_assert (*jump_target);
+	}
+
+      /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs.  */
+      for (tree save_expr : save_exprs)
+	ctx->global->values.remove (save_expr);
+      save_exprs.truncate (0);
+
+      if (++count >= constexpr_loop_limit)
+	{
+	  if (!ctx->quiet)
+	    error_at (rs_expr_loc_or_input_loc (t),
+		      "%<constexpr%> loop iteration count exceeds limit of %d "
+		      "(use %<-fconstexpr-loop-limit=%> to increase the limit)",
+		      constexpr_loop_limit);
+	  *non_constant_p = true;
+	  break;
+	}
+    }
+  while (!returns (jump_target) && !breaks (jump_target)
+	 && !continues (jump_target) && (!switches (jump_target) || count == 0)
+	 && !*non_constant_p);
+
+  /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs.  */
+  for (tree save_expr : save_exprs)
+    ctx->global->values.remove (save_expr);
+
+  return NULL_TREE;
+}
+
 // #include "gt-rust-rust-constexpr.h"
 
 } // namespace Compile
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 01de727320f..f9623a2848a 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1240,6 +1240,10 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 #define DECL_FUNCTION_MEMBER_P(NODE)                                           \
   (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) || DECL_STATIC_FUNCTION_P (NODE))
 
+/* Nonzero if NODE is the target for genericization of 'return' stmts
+   in constructors/destructors of targetm.cxx.cdtor_returns_this targets.  */
+#define LABEL_DECL_CDTOR(NODE) DECL_LANG_FLAG_2 (LABEL_DECL_CHECK (NODE))
+
 #if defined ENABLE_TREE_CHECKING
 
 #define LANG_DECL_MIN_CHECK(NODE)                                              \
@@ -1334,6 +1338,26 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 #define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE)                        \
   (TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE)))
 
+/* WHILE_STMT accessors. These give access to the condition of the
+   while statement and the body of the while statement, respectively.  */
+#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
+#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1)
+
+/* FOR_STMT accessors. These give access to the init statement,
+   condition, update expression, and body of the for statement,
+   respectively.  */
+#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0)
+#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1)
+#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
+#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
+#define FOR_SCOPE(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 4)
+
+/* 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))
+
 // Above macros are copied from gcc/c-family/c-common.h
 
 // Below macros are copied from gcc/cp/name-lookup.cc

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-08-29 15:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 15:33 [gcc/devel/rust/master] rust-constexpr.cc: add more cases to eval_constant_expression() Thomas Schwinge

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