Skip to content

Commit

Permalink
Merge pull request gcc-mirror#55 from NinaRanns/noexcept_observe
Browse files Browse the repository at this point in the history
noexcept_observe
  • Loading branch information
villevoutilainen authored Jan 20, 2025
2 parents b65afb1 + 34bd732 commit d1d1b3a
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 11 deletions.
5 changes: 4 additions & 1 deletion gcc/c-family/c.opt
Original file line number Diff line number Diff line change
Expand Up @@ -1929,9 +1929,12 @@ Enum(p2900_semantic) String(quick_enforce) Value(5)
EnumValue
Enum(p2900_semantic) String(noexcept_enforce) Value(6)

EnumValue
Enum(p2900_semantic) String(noexcept_observe) Value(7)

fcontract-evaluation-semantic=
C++ Joined RejectNegative Enum(p2900_semantic) Var(flag_contract_evaluation_semantic) Init (3)
-fcontract-evaluation-semantic=[ignore|observe|enforce|quick_enforce|noexcept_enforce] Select the contract evaluation semantic (defaults to enforce).
-fcontract-evaluation-semantic=[ignore|observe|enforce|quick_enforce|noexcept_enforce|noexcept_observe] Select the contract evaluation semantic (defaults to enforce).

fcontract-checks-outlined
C++ Var(flag_contract_checks_outlined) Init(1)
Expand Down
26 changes: 18 additions & 8 deletions gcc/cp/contracts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2171,6 +2171,8 @@ get_evaluation_semantic(tree contract)
return CES_QUICK;
case CCS_NOEXCEPT_ENFORCE:
return CES_NOEXCEPT_ENFORCE;
case CCS_NOEXCEPT_OBSERVE:
return CES_NOEXCEPT_OBSERVE;
}
}

Expand Down Expand Up @@ -2375,12 +2377,14 @@ build_contract_check (tree contract)
finish_if_stmt_cond (cond, if_stmt);
/* Using the P2900 names here c++2a ENFORCE=NEVER, OBSERVE=MAYBE. */
if (semantic == CCS_ENFORCE || semantic == CCS_OBSERVE
|| semantic == CCS_NOEXCEPT_ENFORCE)
|| semantic == CCS_NOEXCEPT_ENFORCE
|| semantic == CCS_NOEXCEPT_OBSERVE)
{
tree violation = build_contract_violation (contract,
/*is_const*/true);
build_contract_handler_call (violation,
semantic == CCS_NOEXCEPT_ENFORCE);
bool noexcept_wrap = (semantic == CCS_NOEXCEPT_ENFORCE)
|| (semantic == CCS_NOEXCEPT_OBSERVE);
build_contract_handler_call (violation, noexcept_wrap);
}

if (semantic == CCS_QUICK)
Expand Down Expand Up @@ -2417,7 +2421,8 @@ build_contract_check (tree contract)
violation object or handler. */
tree excp_ = NULL_TREE;
if (semantic == CCS_ENFORCE || semantic == CCS_OBSERVE
|| semantic ==CCS_NOEXCEPT_ENFORCE)
|| semantic ==CCS_NOEXCEPT_ENFORCE
|| semantic == CCS_NOEXCEPT_OBSERVE)
{
excp_ = build_decl (loc, VAR_DECL, NULL, boolean_type_node);
/* compiler-generated. */
Expand All @@ -2433,7 +2438,8 @@ build_contract_check (tree contract)

tree violation = NULL_TREE;
if (semantic == CCS_ENFORCE || semantic == CCS_OBSERVE
|| semantic == CCS_NOEXCEPT_ENFORCE)
|| semantic == CCS_NOEXCEPT_ENFORCE
|| semantic == CCS_NOEXCEPT_OBSERVE)
violation = build_contract_violation (contract, /*is_const*/false);

/* Wrap the contract check in a try-catch. */
Expand All @@ -2446,7 +2452,8 @@ build_contract_check (tree contract)
tree handler = begin_handler ();
finish_handler_parms (NULL_TREE, handler); /* catch (...) */
if (semantic == CCS_ENFORCE || semantic == CCS_OBSERVE
|| semantic == CCS_NOEXCEPT_ENFORCE)
|| semantic == CCS_NOEXCEPT_ENFORCE
|| semantic == CCS_NOEXCEPT_OBSERVE)
{
/* Update the violation object type. */
tree v_type = get_pseudo_contract_violation_type ();
Expand All @@ -2457,7 +2464,9 @@ build_contract_check (tree contract)
r = cp_build_init_expr (r, build_int_cst (integer_type_node,
CDM_EVAL_EXCEPTION));
finish_expr_stmt (r);
build_contract_handler_call (violation, semantic == CCS_NOEXCEPT_ENFORCE);
bool noexcept_wrap = (semantic == CCS_NOEXCEPT_ENFORCE)
|| (semantic == CCS_NOEXCEPT_OBSERVE);
build_contract_handler_call (violation, noexcept_wrap);
/* Note we had an exception. */
finish_expr_stmt (cp_build_init_expr (excp_, boolean_true_node));
}
Expand All @@ -2476,7 +2485,8 @@ build_contract_check (tree contract)
finish_if_stmt_cond (cond, if_not_cond);

if (semantic == CCS_ENFORCE || semantic == CCS_OBSERVE
|| semantic == CCS_NOEXCEPT_ENFORCE)
|| semantic == CCS_NOEXCEPT_ENFORCE
|| semantic == CCS_NOEXCEPT_OBSERVE)
{
tree if_not_excp = begin_if_stmt ();
cond = build_x_unary_op (loc, TRUTH_NOT_EXPR, excp_, NULL_TREE,
Expand Down
7 changes: 5 additions & 2 deletions gcc/cp/contracts.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum contract_level
CCS_NEVER -> enforce
CCS_QUICK -> quick_enforce
CCS_NOEXCEPT_ENFORCE -> noexcept_enforce
CCS_NOEXCEPT_OBSERVE -> noexcept_observe
*/

enum contract_semantic
Expand All @@ -50,7 +51,8 @@ enum contract_semantic
CCS_MAYBE = 4,
CCS_OBSERVE = CCS_MAYBE,
CCS_QUICK = 5,
CCS_NOEXCEPT_ENFORCE
CCS_NOEXCEPT_ENFORCE,
CCS_NOEXCEPT_OBSERVE
};

/* True if the contract is unchecked. */
Expand Down Expand Up @@ -102,7 +104,8 @@ enum contract_evaluation_semantic {
CES_OBSERVE = 2,
CES_ENFORCE = 3,
CES_QUICK = 4,
CES_NOEXCEPT_ENFORCE =5
CES_NOEXCEPT_ENFORCE = 5,
CES_NOEXCEPT_OBSERVE = 6
};

enum constract_detection_mode {
Expand Down
12 changes: 12 additions & 0 deletions gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Test that there is no crash with default contract violation handler and noexcept_observe
// { dg-do compile }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontract-evaluation-semantic=noexcept_observe " }


void f(int i) pre(i > 0){}

int main()
{
f(0);
}

36 changes: 36 additions & 0 deletions gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe2.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//Test that a throwing violation handler causes termination with noexcept-observe
// { dg-do run }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontract-evaluation-semantic=noexcept_observe " }
#include <experimental/contract>
#include <exception>
#include <cstdlib>

void my_term()
{
try { throw; }
catch(int) { std::exit(0); }
}
void handle_contract_violation(const std::experimental::contract_violation& violation)
{
throw 1;
}

struct X
{
void f(const int x) pre(x>1) post(x>3) {
int i = 1;
}
};

int main()
{
std::set_terminate (my_term);
try
{
X x;
x.f(-42);
} catch (...) {
}
// We should not get here
return 1;
}
32 changes: 32 additions & 0 deletions gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe3.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//Test that a throwing violation handler causes termination with noexcept-observe
// { dg-do run }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontract-evaluation-semantic=noexcept_observe " }
#include <experimental/contract>
#include <exception>
#include <cstdlib>

void my_term()
{
try { throw; }
catch(int) { std::exit(0); }
}

void handle_contract_violation(const std::experimental::contract_violation& violation)
{
throw 1;
}

void f(int x) pre(x >= 0)
{
}

int main()
{
std::set_terminate (my_term);
try
{
f(-42);
} catch (...) {}
// We should not get here
return 1;
}
15 changes: 15 additions & 0 deletions gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe4.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//Test that noexcept-observe with a non throwing violation handler has
// observe semantics
// { dg-do run }
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontract-evaluation-semantic=noexcept_observe " }

int f(const int a, const int b) pre (a > 2) post(r : r > 2){ return 1;};

int main(int, char**)
{
f(1,1);
return 0;
}

// { dg-output "contract violation in function f at .*: a > 2.*(\n|\r\n|\r)" }
// { dg-output "contract violation in function f at .*: r > 2.*(\n|\r\n|\r)" }

0 comments on commit d1d1b3a

Please sign in to comment.