public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/c++-contracts] c++: share code between [[assert]] and contracts
@ 2022-11-01 11:43 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-11-01 11:43 UTC (permalink / raw)
  To: gcc-cvs

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

commit d7cb97b26da508121906038465609b6437121461
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Oct 21 10:48:15 2022 -0400

    c++: share code between [[assert]] and contracts
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_assert): Factor out from...
            (cxx_eval_internal_function): ...here.
            (cxx_eval_constant_expression): Also use it for contracts.
            * contracts.cc (build_contract_check): Use build_assume_call.

Diff:
---
 gcc/cp/constexpr.cc | 136 +++++++++++++++++++++++++++-------------------------
 gcc/cp/contracts.cc |  36 +++++---------
 2 files changed, 82 insertions(+), 90 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 9617bca94ec..b3041d9c3d3 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "fold-const.h"
+#include "intl.h"
 
 static bool verify_constant (tree, bool, bool *, bool *);
 #define VERIFY_CONSTANT(X)						\
@@ -1887,7 +1888,8 @@ find_failing_clause_r (const constexpr_ctx *ctx, tree expr)
 	e = find_failing_clause_r (ctx, TREE_OPERAND (expr, 1));
       return e;
     }
-  tree e = fold_operand (expr, ctx);
+  tree e = contextual_conv_bool (expr, tf_none);
+  e = fold_operand (e, ctx);
   if (integer_zerop (e))
     /* This is the failing clause.  */
     return expr;
@@ -1935,6 +1937,61 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p,
     inform (cloc, "%qE evaluates to false", bad);
 }
 
+/* Process an assert/assume of ORIG_ARG.  If it's not supposed to be evaluated,
+   do it without changing the current evaluation state.  If it evaluates to
+   false, complain and return false; otherwise, return true.  */
+
+static bool
+cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg,
+		 location_t loc, bool evaluated,
+		 bool *non_constant_p, bool *overflow_p)
+{
+  if (*non_constant_p)
+    return true;
+
+  tree eval;
+  if (!evaluated)
+    {
+      if (!potential_rvalue_constant_expression (arg))
+	return true;
+
+      constexpr_ctx new_ctx = *ctx;
+      new_ctx.quiet = true;
+      bool new_non_constant_p = false, new_overflow_p = false;
+      /* Avoid modification of existing values.  */
+      modifiable_tracker ms (new_ctx.global);
+      eval = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
+					   &new_non_constant_p,
+					   &new_overflow_p);
+    }
+  else
+    eval = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
+					 non_constant_p,
+					 overflow_p);
+  if (!*non_constant_p && integer_zerop (eval))
+    {
+      if (!ctx->quiet)
+	{
+	  /* See if we can find which clause was failing
+	     (for logical AND).  */
+	  tree bad = find_failing_clause (ctx, arg);
+	  /* If not, or its location is unusable, fall back to the
+	     previous location.  */
+	  location_t cloc = cp_expr_loc_or_loc (bad, loc);
+
+	  /* Report the error. */
+	  auto_diagnostic_group d;
+	  error_at (cloc, msg);
+	  diagnose_failing_condition (bad, cloc, true, ctx);
+	  return bad;
+	}
+      *non_constant_p = true;
+      return false;
+    }
+
+  return true;
+}
+
 /* Evaluate a call T to a GCC internal function when possible and return
    the evaluated result or, under the control of CTX, give an error, set
    NON_CONSTANT_P, and return the unevaluated call T otherwise.  */
@@ -1955,41 +2012,11 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
       return void_node;
 
     case IFN_ASSUME:
-      if (potential_rvalue_constant_expression (CALL_EXPR_ARG (t, 0)))
-	{
-	  constexpr_ctx new_ctx = *ctx;
-	  new_ctx.quiet = true;
-	  tree arg = CALL_EXPR_ARG (t, 0);
-	  bool new_non_constant_p = false, new_overflow_p = false;
-	  /* Avoid modification of existing values.  */
-	  modifiable_tracker ms (new_ctx.global);
-	  arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
-					      &new_non_constant_p,
-					      &new_overflow_p);
-	  if (!new_non_constant_p && !new_overflow_p && integer_zerop (arg))
-	    {
-	      if (!*non_constant_p && !ctx->quiet)
-		{
-		  /* See if we can find which clause was failing
-		     (for logical AND).  */
-		  tree bad = find_failing_clause (&new_ctx,
-						  CALL_EXPR_ARG (t, 0));
-		  /* If not, or its location is unusable, fall back to the
-		     previous location.  */
-		  location_t cloc = cp_expr_loc_or_loc (bad, EXPR_LOCATION (t));
-
-		  auto_diagnostic_group d;
-
-		  /* Report the error. */
-		  error_at (cloc,
-			    "failed %<assume%> attribute assumption");
-		  diagnose_failing_condition (bad, cloc, false, &new_ctx);
-		}
-
-	      *non_constant_p = true;
-	      return t;
-	    }
-	}
+      if (!cxx_eval_assert (ctx, CALL_EXPR_ARG (t, 0),
+			    G_("failed %<assume%> attribute assumption"),
+			    EXPR_LOCATION (t), /*eval*/false,
+			    non_constant_p, overflow_p))
+	return t;
       return void_node;
 
     case IFN_ADD_OVERFLOW:
@@ -7852,36 +7879,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	if (semantic == CCS_IGNORE)
 	  break;
 
-	tree c = CONTRACT_CONDITION (t);
-	if (semantic == CCS_ASSUME)
-	  {
-#if 0
-	    /* For an assume contract, try evaluating it without instantiating
-	       anything.  If non-constant, assume it's satisfied.  */
-	    /* This breaks contracts-assume6.C.  */
-
-	    if (!cp_tree_defined_p (c))
-	      break;
-#endif
-
-	    bool dummy_nc = false, dummy_ov = false;
-	    constexpr_ctx new_ctx = *ctx;
-	    new_ctx.quiet = true;
-	    r = cxx_eval_constant_expression (&new_ctx, c, vc_prvalue,
-					      &dummy_nc, &dummy_ov);
-	    if (dummy_nc)
-	      break;
-	  }
-	else
-	  /* Evaluate the generated check.  */
-	  r = cxx_eval_constant_expression (ctx, c, vc_prvalue, non_constant_p,
-					    overflow_p);
-	if (r == boolean_false_node)
-	  {
-	    if (!ctx->quiet)
-	      error_at (EXPR_LOCATION (c), "contract predicate %qE is %qE", c, r);
-	    *non_constant_p = true;
-	  }
+	if (!cxx_eval_assert (ctx, CONTRACT_CONDITION (t),
+			      G_("contract predicate is false in "
+				 "constant expression"),
+			      EXPR_LOCATION (t), checked_contract_p (semantic),
+			      non_constant_p, overflow_p))
+	  *non_constant_p = true;
+	r = void_node;
       }
       break;
 
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 11fd93362f3..0a1626d6b68 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -58,8 +58,6 @@ along with GCC; see the file COPYING3.  If not see
    Assumed contracts have a similar transformation that results the body of the
    if being __builtin_unreachable ();
 
-   FIXME use build_assume_call.
-
    Parsing of pre and post contract conditions need to be deferred when the
    contracts are attached to a member function. The postcondition identifier
    cannot be used before the deduced return type of an auto function is used,
@@ -1659,38 +1657,28 @@ build_contract_check (tree contract)
   if (condition == error_mark_node)
     return NULL_TREE;
 
-  /* If an assumed contract condition is not fully defined, the current method
-     of turning it into a compile time assumption fails and emits run time
-     code.  We don't want that, so just turn these into NOP.  */
-  if (semantic == CCS_ASSUME && !cp_tree_defined_p (condition))
-    return void_node;
+  location_t loc = EXPR_LOCATION (contract);
+
+  if (semantic == CCS_ASSUME)
+    return build_assume_call (loc, condition);
 
   tree if_stmt = begin_if_stmt ();
-  tree cond = build_x_unary_op (EXPR_LOCATION (contract),
+  tree cond = build_x_unary_op (loc,
 				TRUTH_NOT_EXPR,
 				condition, NULL_TREE,
 				tf_warning_or_error);
   finish_if_stmt_cond (cond, if_stmt);
 
-  if (semantic == CCS_ASSUME)
+  /* Get the continuation mode.  */
+  contract_continuation cmode;
+  switch (semantic)
     {
-      tree unreachable_fn = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
-      tree call = build_call_n (unreachable_fn, 0);
-      finish_expr_stmt (call);
+    case CCS_NEVER: cmode = NEVER_CONTINUE; break;
+    case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
+    default: gcc_unreachable ();
     }
-  else
-    {
-      /* Get the continuation mode.  */
-      contract_continuation cmode;
-      switch (semantic)
-	{
-	  case CCS_NEVER: cmode = NEVER_CONTINUE; break;
-	  case CCS_MAYBE: cmode = MAYBE_CONTINUE; break;
-	  default: gcc_unreachable ();
-	}
 
-      build_contract_handler_call (contract, cmode);
-    }
+  build_contract_handler_call (contract, cmode);
 
   finish_then_clause (if_stmt);
   tree scope = IF_SCOPE (if_stmt);

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

only message in thread, other threads:[~2022-11-01 11:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-01 11:43 [gcc/devel/c++-contracts] c++: share code between [[assert]] and contracts Jason Merrill

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).