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