diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index c27a57ae1d123..7e425132affbe 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -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) diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index 37d10cd389364..94f65962cef12 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -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; } } @@ -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) @@ -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. */ @@ -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. */ @@ -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 (); @@ -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)); } @@ -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, diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h index 81172e5247c04..78259e389c517 100644 --- a/gcc/cp/contracts.h +++ b/gcc/cp/contracts.h @@ -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 @@ -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. */ @@ -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 { diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe.C b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe.C new file mode 100644 index 0000000000000..bd52cc2d4dc6b --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe.C @@ -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); +} + diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe2.C b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe2.C new file mode 100644 index 0000000000000..e88d99728f92d --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe2.C @@ -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 +#include +#include + +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; +} diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe3.C b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe3.C new file mode 100644 index 0000000000000..87d777ff81354 --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe3.C @@ -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 +#include +#include + +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; +} diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe4.C b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe4.C new file mode 100644 index 0000000000000..f64d54ea19dd8 --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/cpp26/noexcept-observe4.C @@ -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)" }