This adds in a set of tests for the base C++26 contracts, and also ensures
that cases that previously failed with attribute syntax continue to work as
expected with the revised C++26 syntax.
PR c++/113968
PR c++/110871
PR c++/110872
gcc/testsuite/ChangeLog:
* g++.dg/contracts/cpp26/BZ121936-workaround-noipa.C: New test.
* g++.dg/contracts/cpp26/assertion-statement-errors.C: New test.
* g++.dg/contracts/cpp26/assertion-statement.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p11-observe.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p14.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-2.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-3.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-4.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-5.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-post.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-pre.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF2.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF3.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF4.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p17.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p4-error.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p4.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p6.C: New test.
* g++.dg/contracts/cpp26/basic.contract.eval.p6.observe.C: New test.
* g++.dg/contracts/cpp26/basic.scope.contract.p1.C: New test.
* g++.dg/contracts/cpp26/basic.scope.contract.p2.1.C: New test.
* g++.dg/contracts/cpp26/contract-assert-run.C: New test.
* g++.dg/contracts/cpp26/contract-assert-warn-attributes.C: New test.
* g++.dg/contracts/cpp26/contract-violation-noexcept.C: New test.
* g++.dg/contracts/cpp26/contract-violation-noexcept2.C: New test.
* g++.dg/contracts/cpp26/contract_genericize.C: New test.
* g++.dg/contracts/cpp26/contracts-friend1.C: New test.
* g++.dg/contracts/cpp26/contracts-nested-class1.C: New test.
* g++.dg/contracts/cpp26/contracts-nested-class2.C: New test.
* g++.dg/contracts/cpp26/contracts-tmpl-spec2.C: New test.
* g++.dg/contracts/cpp26/dcl.contract.func.p4.C: New test.
* g++.dg/contracts/cpp26/dcl.contract.func.p6.C: New test.
* g++.dg/contracts/cpp26/dcl.contract.res.p1-NT.C: New test.
* g++.dg/contracts/cpp26/dcl.contract.res.p1.C: New test.
* g++.dg/contracts/cpp26/dcl.contract.res.p2.C: New test.
* g++.dg/contracts/cpp26/debug-and-opt.C: New test.
* g++.dg/contracts/cpp26/deferred1.C: New test.
* g++.dg/contracts/cpp26/dependent_contract.C: New test.
* g++.dg/contracts/cpp26/empty-nt-param.C: New test.
* g++.dg/contracts/cpp26/function-contract-specifier-seq-error.C: New
test.
* g++.dg/contracts/cpp26/function-contract-specifier-seq.C: New test.
* g++.dg/contracts/cpp26/lambda.C: New test.
* g++.dg/contracts/cpp26/name_mangling.C: New test.
* g++.dg/contracts/cpp26/over.call.func.p3.1.C: New test.
* g++.dg/contracts/cpp26/pr113968.C: New test.
* g++.dg/contracts/cpp26/src-loc-0.C: New test.
* g++.dg/contracts/cpp26/src-loc-1.C: New test.
* g++.dg/contracts/cpp26/src-loc-2.C: New test.
* g++.dg/contracts/cpp26/throwing-violation-handler.cc: New test.
* g++.dg/contracts/cpp26/unused_warning.C: New test.
* g++.dg/contracts/cpp26/vaargs.C: New test.
* g++.dg/contracts/cpp2a/check-err.C: New test.
* g++.dg/coroutines/pr110871.C: New test.
* g++.dg/coroutines/pr110872.C: New test.
Co-Authored-by: Nina Ranns <[email protected]>
Co-Authored-by: Ville Voutilainen <[email protected]>
Signed-off-by: Iain Sandoe <[email protected]>
---
.../cpp26/BZ121936-workaround-noipa.C | 22 +
.../cpp26/assertion-statement-errors.C | 41 ++
.../contracts/cpp26/assertion-statement.C | 34 ++
.../cpp26/basic.contract.eval.p11-observe.C | 31 ++
.../contracts/cpp26/basic.contract.eval.p14.C | 25 +
.../cpp26/basic.contract.eval.p17-2.C | 47 ++
.../cpp26/basic.contract.eval.p17-3.C | 58 +++
.../cpp26/basic.contract.eval.p17-4.C | 55 +++
.../cpp26/basic.contract.eval.p17-5.C | 52 ++
.../cpp26/basic.contract.eval.p17-SMF-post.C | 54 +++
.../cpp26/basic.contract.eval.p17-SMF-pre.C | 54 +++
.../cpp26/basic.contract.eval.p17-SMF2.C | 57 +++
.../cpp26/basic.contract.eval.p17-SMF3.C | 56 +++
.../cpp26/basic.contract.eval.p17-SMF4.C | 56 +++
.../contracts/cpp26/basic.contract.eval.p17.C | 49 ++
.../cpp26/basic.contract.eval.p4-error.C | 14 +
.../contracts/cpp26/basic.contract.eval.p4.C | 27 ++
.../contracts/cpp26/basic.contract.eval.p6.C | 31 ++
.../cpp26/basic.contract.eval.p6.observe.C | 17 +
.../contracts/cpp26/basic.scope.contract.p1.C | 42 ++
.../cpp26/basic.scope.contract.p2.1.C | 11 +
.../contracts/cpp26/contract-assert-run.C | 55 +++
.../cpp26/contract-assert-warn-attributes.C | 7 +
.../cpp26/contract-violation-noexcept.C | 112 +++++
.../cpp26/contract-violation-noexcept2.C | 38 ++
.../contracts/cpp26/contract_genericize.C | 49 ++
.../contracts/cpp26/contracts-friend1.C | 36 ++
.../contracts/cpp26/contracts-nested-class1.C | 23 +
.../contracts/cpp26/contracts-nested-class2.C | 38 ++
.../contracts/cpp26/contracts-tmpl-spec2.C | 446 ++++++++++++++++++
.../contracts/cpp26/dcl.contract.func.p4.C | 126 +++++
.../contracts/cpp26/dcl.contract.func.p6.C | 21 +
.../contracts/cpp26/dcl.contract.res.p1-NT.C | 146 ++++++
.../contracts/cpp26/dcl.contract.res.p1.C | 21 +
.../contracts/cpp26/dcl.contract.res.p2.C | 25 +
.../g++.dg/contracts/cpp26/debug-and-opt.C | 15 +
.../g++.dg/contracts/cpp26/deferred1.C | 49 ++
.../contracts/cpp26/dependent_contract.C | 32 ++
.../g++.dg/contracts/cpp26/empty-nt-param.C | 42 ++
.../function-contract-specifier-seq-error.C | 50 ++
.../cpp26/function-contract-specifier-seq.C | 122 +++++
gcc/testsuite/g++.dg/contracts/cpp26/lambda.C | 5 +
.../g++.dg/contracts/cpp26/name_mangling.C | 15 +
.../contracts/cpp26/over.call.func.p3.1.C | 36 ++
.../g++.dg/contracts/cpp26/pr113968.C | 23 +
.../g++.dg/contracts/cpp26/src-loc-0.C | 18 +
.../g++.dg/contracts/cpp26/src-loc-1.C | 18 +
.../g++.dg/contracts/cpp26/src-loc-2.C | 20 +
.../cpp26/throwing-violation-handler.cc | 23 +
.../g++.dg/contracts/cpp26/unused_warning.C | 25 +
gcc/testsuite/g++.dg/contracts/cpp26/vaargs.C | 35 ++
.../g++.dg/contracts/cpp2a/check-err.C | 18 +
gcc/testsuite/g++.dg/coroutines/pr110871.C | 64 +++
gcc/testsuite/g++.dg/coroutines/pr110872.C | 50 ++
54 files changed, 2636 insertions(+)
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/BZ121936-workaround-noipa.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p11-observe.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p14.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-2.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-3.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-4.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-5.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-post.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-pre.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF2.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF3.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF4.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4-error.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.observe.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p1.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p2.1.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-run.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-warn-attributes.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept2.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/contract_genericize.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/contracts-friend1.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class1.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class2.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/contracts-tmpl-spec2.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p4.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p6.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1-NT.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p2.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/debug-and-opt.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/deferred1.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/dependent_contract.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/empty-nt-param.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq-error.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/lambda.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/name_mangling.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/over.call.func.p3.1.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr113968.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/src-loc-0.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/src-loc-1.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/src-loc-2.C
create mode 100644
gcc/testsuite/g++.dg/contracts/cpp26/throwing-violation-handler.cc
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/unused_warning.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/vaargs.C
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp2a/check-err.C
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr110871.C
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr110872.C
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/BZ121936-workaround-noipa.C
b/gcc/testsuite/g++.dg/contracts/cpp26/BZ121936-workaround-noipa.C
new file mode 100644
index 00000000000..ceb01447b39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/BZ121936-workaround-noipa.C
@@ -0,0 +1,22 @@
+// check that we do not optimise based on contract_asssert
+// { dg-additional-options "-O3 -fcontracts
-fcontract-evaluation-semantic=quick_enforce -fdump-tree-optimized " }
+// { dg-do compile { target c++23 } }
+
+[[gnu::used, gnu::noinline]]
+inline int* f(int *y) {
+ contract_assert(y != nullptr);
+ return y;
+}
+
+
+int foo(int *x) {
+ if (f(x) == nullptr)
+ {
+ return 0;
+ }
+ return *x;
+}
+
+// Check that the if condition in foo isn't optimised away, we should see the
+// nullptr check twice.
+// { dg-final { scan-tree-dump-times {if \([^=]+== 0B\)} 2 "optimized" } }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
new file mode 100644
index 00000000000..660200a9b5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
@@ -0,0 +1,41 @@
+// generic assertion-statement parsing checks
+// N5008
+// assertion-statement :
+// contract_assert attribute-specifier-seq opt ( conditional-expression ) ;
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+// { dg-prune-output "not declared" }
+
+static_assert (__cpp_contracts >= 202502L);
+
+contract_assert f(); // { dg-error "expected unqualified-id before
.contract_assert." }
+
+void f(contract_assert); // { dg-error "expected primary-expression
before|declared void" }
+struct contract_assert{}; // { dg-error "expected unqualified-id
before|expected identifier" }
+void contract_assert(); // { dg-error "expected unqualified-id before" }
+
+void g(){};
+int main()
+{
+ contract_assert(x==0); // { dg-error ".x. was not declared in this scope"}
+ contract_assert int i = 0; // // { dg-error "expected primary-expression
before|before .int." }
+
+ i = 7;
+
+ int j = 4;
+
+ contract_assert( x = 0); // { dg-error "expected primary-expression
before|expected .\\). before .=. token" }
+
+ contract_assert( y == 0); // { dg-error ".y. was not declared in this
scope" }
+
+ contract_assert(true) // { dg-error "expected .;. before .int." }
+ int k = 4;
+
+ contract_assert(true) // { dg-error "expected .;. before .g." }
+ g();
+
+ contract_assert [[deprecated]] (i == 3); // { dg-warning "attributes are
ignored on contract assertions" }
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
new file mode 100644
index 00000000000..043785d0074
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
@@ -0,0 +1,34 @@
+// generic assertion-statement parsing checks
+// N5008
+// assertion-statement :
+// contract_assert attribute-specifier-seq opt ( conditional-expression ) ;
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+static_assert (__cpp_contracts >= 202502L);
+
+int main()
+{
+ int x;
+
+ contract_assert( x >= 0);
+ contract_assert( x < 0);
+ contract_assert( x == 0);
+
+ contract_assert( x > 0 ? true : false);
+ contract_assert( x < 0 ? true : false);
+
+ contract_assert( x >= 0);
+ contract_assert( x >= 0);
+ contract_assert( x >= 0);
+ contract_assert( x >= 0);
+
+ contract_assert( x >= 0);
+ contract_assert( x < 0);
+ contract_assert( x == 0);
+ contract_assert( x == 1);
+
+
+
+ return 0;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p11-observe.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p11-observe.C
new file mode 100644
index 00000000000..b35d0743dca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p11-observe.C
@@ -0,0 +1,31 @@
+// N5008 :
+// dcl.contract.res/p1
+// If a contract violation occurs in a context that is not manifestly
constant-evaluated and the evaluation
+// semantic is enforce or observe, the contract-violation handler (6.10.3) is
invoked with an lvalue referring to
+// n object v of type const std::contracts::contract_violation (17.10.3)
containing information about
+// the contract violation. Storage for v is allocated in an unspecified manner
except as noted in 6.7.6.5.2. The
+// lifetime of v persists for the duration of the invocation of the
contract-violation handler.
+//
+// Check the contract violation information in observe semantic
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+
+int f(int i, int j = 1) pre(i > 0) post(r: r < 5)
+{
+ contract_assert( j > 0);
+ return i;
+}
+
+
+int main(int, char**)
+{
+ f(5);
+ f(0,0);
+}
+// { dg-output "contract violation in function int f.int, int. at .*: r <
5.*(\n|\r\n|\r)" }
+// { dg-output ".assertion_kind: post, semantic: observe, mode:
predicate_false, terminating: no.*(\n|\r\n|\r)" }
+// { dg-output "contract violation in function int f.int, int. at .*: i >
0.*(\n|\r\n|\r)" }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.*(\n|\r\n|\r)" }
+// { dg-output "contract violation in function int f.int, int. at .*: j >
0.*(\n|\r\n|\r)" }
+// { dg-output ".assertion_kind: assert, semantic: observe, mode:
predicate_false, terminating: no.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p14.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p14.C
new file mode 100644
index 00000000000..029a1cef860
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p14.C
@@ -0,0 +1,25 @@
+// N5008 :
+// basic.contract.eval/p14
+// Note 10 : If the contract-violation handler returns normally and the
evaluation semantic is observe, control flow
+// continues normally after the point of evaluation of the contract assertion.
??? end note
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+
+bool check(int i){
+ if (i > 10)
+ throw 3;
+
+ return true;
+}
+
+void f() pre(check(15)){}
+
+
+int main(int, char**)
+{
+
+ f();
+}
+
+// { dg-output "contract violation in function void f.. at .*:
check.15..*(\n|\r\n|\r)" }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
evaluation_exception: threw an instance of .int., terminating:
no.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-2.C
new file mode 100644
index 00000000000..e21641b9f31
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-2.C
@@ -0,0 +1,47 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+void f(int x) noexcept pre(x>1)
+{
+ try{
+ int i = 1;
+ }
+ catch(...) {}
+}
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ f(-42);
+ } catch (...) {}
+ // We should not get here
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-3.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-3.C
new file mode 100644
index 00000000000..ac2c80e2b09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-3.C
@@ -0,0 +1,58 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 13 : If a contract-violation handler invoked from an
assertion-statement (8.8)) exits via an exception, the search
+// for a handler continues from the execution of that statement. ??? end note]
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+void free_f(const int x) {
+ try {
+ contract_assert(x>1);
+ int i = 1;
+ }
+ catch(...){}
+}
+
+struct X
+{
+ void f(const int x) {
+ try {
+ contract_assert(x>1);
+ int i = 1;
+ }
+ catch(...){}
+ }
+
+ virtual void virt_f(const int x) {
+ try {
+ contract_assert(x>1);
+ int i = 1;
+ }
+ catch(...){}
+ }
+
+};
+
+int main()
+{
+ free_f(-42);
+
+ X x;
+ x.f(-42);
+ x.virt_f(-42);
+
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-4.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-4.C
new file mode 100644
index 00000000000..68cabc8106c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-4.C
@@ -0,0 +1,55 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a post condition on a member function
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+struct X
+{
+ void f(const int x) noexcept post(x>1)
+ {
+ try{
+ int i = 1;
+ }
+ catch(...) {}
+ }
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x;
+ x.f(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-5.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-5.C
new file mode 100644
index 00000000000..c071eb9ecc7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-5.C
@@ -0,0 +1,52 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a pre condition on a member function
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+struct X
+{
+ void f(int x) noexcept pre(x>1) {
+ int i = 1;
+ }
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x;
+ x.f(-42);
+ } catch (...) {
+ }
+
+ // We should not get here
+ __builtin_abort ();
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-post.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-post.C
new file mode 100644
index 00000000000..2157fe7e44f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-post.C
@@ -0,0 +1,54 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a post condition on a constructor with function
+// try block
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+struct X
+{
+
+ X(const int x) noexcept post(x>1) try
+ {
+ int i = 1;
+ }
+ catch(...) {}
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-pre.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-pre.C
new file mode 100644
index 00000000000..d7152ca141a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF-pre.C
@@ -0,0 +1,54 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a pre condition on a constructor with function
+// try block
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+struct X
+{
+
+ X(int x) noexcept pre(x>1) try
+ {
+ int i = 1;
+ }
+ catch(...) {}
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF2.C
new file mode 100644
index 00000000000..65506df8ac0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF2.C
@@ -0,0 +1,57 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a pre condition on a constructor
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+struct X
+{
+
+ X(int x) noexcept pre(x>1)
+ {
+ try{
+ int i = 1;
+ }
+ catch(...) {
+ }
+ }
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF3.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF3.C
new file mode 100644
index 00000000000..f6a22aa2148
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF3.C
@@ -0,0 +1,56 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a pre condition on a destructor
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+const int x = -42;
+
+struct X
+{
+
+ ~X() noexcept pre(x>1)
+ {
+ try{}
+ catch(...){
+ }
+ }
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x;
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF4.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF4.C
new file mode 100644
index 00000000000..f1ba70083c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17-SMF4.C
@@ -0,0 +1,56 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+//
+// This tests the behaviour of a pre condition on an implictly noexcept
+// destructor
+//
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+const int x = -42;
+
+struct X
+{
+
+ ~X() pre(x>1) try
+ {
+ }
+ catch(...) {}
+};
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ X x;
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17.C
new file mode 100644
index 00000000000..a5edc8f2c8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p17.C
@@ -0,0 +1,49 @@
+// N5008:
+// basic.contract.eval/p17
+// If a contract-violation handler invoked from the evaluation of a function
contract assertion (9.4.1) exits via
+// an exception, the behavior is as if the function body exits via that same
exception.
+// [Note 12 : A function-try-block (14.1) is the function body when present
and thus does not have an opportunity to
+// catch the exception. If the function has a non-throwing exception
specification, the function std::terminate is
+// invoked (14.6.2). ??? end note]
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <contracts>
+#include <exception>
+#include <cstdlib>
+
+struct MyException{};
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ try { throw; }
+ catch(MyException) { std::exit(0); }
+}
+
+
+void handle_contract_violation(const std::contracts::contract_violation&
violation)
+{
+ throw MyException{};
+}
+
+void f(const int x) noexcept post(x>1)
+{
+ try{
+ int i = 1;
+ }
+ catch(...) {
+ }
+}
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ f(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ __builtin_abort ();
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4-error.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4-error.C
new file mode 100644
index 00000000000..fd07994d860
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4-error.C
@@ -0,0 +1,14 @@
+// N5008 :
+// basic.contract.eval/p4
+// The evaluation of a contract assertion using the ignore semantic has no
effect.
+// [Note 2 : The predicate is potentially evaluated (6.3), but not evaluated.
??? end note]
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=ignore"
}
+
+struct S;
+int f(int i, int j = 1)
+ pre (check(i)) // { dg-error "was not declared in this scope" }
+{
+ contract_assert ( S{}.member ); // { dg-error "invalid use of incomplete
type" }
+ return i;
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4.C
new file mode 100644
index 00000000000..dae2382ba67
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p4.C
@@ -0,0 +1,27 @@
+// N5008 :
+// basic.contract.eval/p4
+// The evaluation of a contract assertion using the ignore semantic has no
effect.
+// [Note 2 : The predicate is potentially evaluated (6.3), but not evaluated.
??? end note]
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=ignore"
}
+
+#include <contracts>
+
+int f(int i, int j = 1)
+ pre (i > 0)
+ post (r: r < 5)
+{
+ contract_assert ( j > 0);
+ return i;
+}
+
+int main(int, char**)
+{
+ f (0,0);
+}
+
+void
+handle_contract_violation (const std::contracts::contract_violation &)
+{
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.C
new file mode 100644
index 00000000000..2c118e16554
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.C
@@ -0,0 +1,31 @@
+// N5008 :
+// basic.contract.eval/p6
+// There is an observable checkpoint ([intro.abstract]) C that happens before
+// (evaluation of a contract assertion ) A such that any other operation O
+// that happens before A also happens before C
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -O -fdump-tree-original
-fdump-tree-optimized -Wno-return-type" }
+int f(int& i)
+{
+ i++;
+ return i;
+}
+
+int f2 (int x, const int *y)
+{
+ int b = x + *y;
+}
+
+int main(int ac, char *av[])
+{
+ int i = 3;
+ *av[0] = (char) f(i);
+ contract_assert (f2(i, &i) > 42);
+ return i;
+}
+// Check that
+// - observable checkpoint has been added to the contract_assert
+// - observable has been removed from the optimized tree
+
+// { dg-final { scan-tree-dump "__builtin_observable" "original" } }
+// { dg-final { scan-tree-dump "_2 = 4" "optimized" } }
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.observe.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.observe.C
new file mode 100644
index 00000000000..60b17f24fe7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.contract.eval.p6.observe.C
@@ -0,0 +1,17 @@
+// N5008 :
+// basic.contract.eval/p6
+// There is an observable checkpoint ([intro.abstract]) C that happens before
+// (evaluation of a contract assertion ) A such that any other operation O
+// that happens before A also happens before C
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
-fdump-tree-gimple " }
+
+
+int main(int ac, char *av[])
+{
+ int i = ac;
+ contract_assert (i == 3);
+ return i;
+}
+
+// { dg-final { scan-tree-dump
"__builtin_observable.*__tu_has_violation.*__builtin_observable" "gimple" } }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p1.C
new file mode 100644
index 00000000000..389d4d03f88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p1.C
@@ -0,0 +1,42 @@
+// N5008
+// basic.scope.contract/p1
+// Each contract assertion (6.10) C introduces a contract-assertion scope that
includes C.
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+// Check that result vars are not visible in function bodies.
+
+int free_fn (int x)
+ post (r: r > 5);
+
+int free_fn (int x)
+ post (r: r > 5)
+{ r += 1; return r;} // { dg-error {'r' was not declared in this scope} }
+
+struct X {
+ int fn0 (int x)
+ post (res: res > 5)
+ { res = 15; return res; } // { dg-error {'res' was not declared in this
scope} }
+
+ int fn1 (int x)
+ post (res: res > 5);
+};
+
+int
+X::fn1 (int y)
+ post (ans: ans > 5)
+ { ans = 15; return 1; } // { dg-error {'ans' was not declared in this
scope} }
+
+template <class T>
+int
+postcond (T x) post (res: res > 3);
+
+template <class T>
+int
+postcond (T x) post (out: out > 3)
+{ out = 5; return x; } // { dg-error {'out' was not declared in this scope} }
+
+int foo (int x)
+{
+ return postcond (4);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p2.1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p2.1.C
new file mode 100644
index 00000000000..b2a198b45c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/basic.scope.contract.p2.1.C
@@ -0,0 +1,11 @@
+// N5008 :
+// basic.scope.contract/p2.1
+// If a result-name-introducer (9.4.2) that is not name-independent (6.4.1)
and whose enclosing postcondition
+// assertion is associated with a function F potentially conflicts with a
declaration whose target scope is
+// - the function parameter scope of F or
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+int bad_mr_shadow (int r)
+ post (r: r > 5) // { dg-error "contract postcondition result names must not
shadow function parameters" }
+ { return r + 1; }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-run.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-run.C
new file mode 100644
index 00000000000..5e47ea3216c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-run.C
@@ -0,0 +1,55 @@
+// generic assert contract parsing checks
+// check omitted, 'default', 'audit', and 'axiom' contract levels parse
+// check that all concrete semantics parse
+// check omitted, '%default' contract roles parse
+// ensure that an invalid contract level 'invalid' errors
+// ensure that a predicate referencing an undefined variable errors
+// ensure that a missing colon after contract level errors
+// ensure that an invalid contract role 'invalid' errors
+// ensure that a missing colon after contract role errors
+// { dg-do run }
+// { dg-options "-std=c++2a -fcontracts
-fcontract-evaluation-semantic=observe" }
+#include <iostream>
+#include <contracts>
+
+#define VERIFY_ASSERT(statement, asserts) \
+ { \
+ bool violation = false;\
+ try{ \
+ statement; \
+ } catch(int &ex) { \
+ violation = true; \
+ } \
+ if ((asserts && !violation) || (!(asserts) && violation))
__builtin_abort(); \
+ } \
+
+static_assert (__cpp_contracts >= 202502L);
+
+void handle_contract_violation(const std::contracts::contract_violation
&violation) {
+ std::cerr << "custom std::handle_contract_violation called:"
+ << " " << violation.location().line()
+ << " " << violation.location().file_name()
+ << std::endl;
+ throw -(int)violation.location().line();
+}
+
+void foo(int x) pre (x>10){};
+
+int main()
+{
+
+ VERIFY_ASSERT(contract_assert(true), false);
+ VERIFY_ASSERT(contract_assert(false), true);
+
+ int i = 4;
+ VERIFY_ASSERT(foo(i), true);
+ VERIFY_ASSERT(contract_assert( i == 4 ? true : false), false)
+ VERIFY_ASSERT(contract_assert( i > 4 ? true : false), true)
+
+ i = 18;
+ VERIFY_ASSERT(foo(i), false);
+ VERIFY_ASSERT(contract_assert( i == 4 ? true : false), true)
+ VERIFY_ASSERT(contract_assert( i > 4 ? true : false), false)
+
+ return 0;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-warn-attributes.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-warn-attributes.C
new file mode 100644
index 00000000000..5da1c72ed0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contract-assert-warn-attributes.C
@@ -0,0 +1,7 @@
+// { dg-options "-std=c++26 -fcontracts " }
+
+int foo (int x)
+pre [[unlikley]] ( x > 41 ) // { dg-warning "attributes are ignored on
function contract specifiers" }
+{
+ return x + 1;
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept.C
new file mode 100644
index 00000000000..b7203936fe1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept.C
@@ -0,0 +1,112 @@
+// test that the default contract violation handler can't throw
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+#include <iostream>
+#include <exception>
+#include <cstdlib>
+
+// Throws on all overflow and underflow calls.
+struct underflow_error: std::exception { };
+struct overflow_error: std::exception { };
+struct positioning_error: std::exception { };
+
+template<typename T>
+struct fail_buf
+ : public T
+{
+ typedef typename T::char_type char_type;
+ typedef typename T::int_type int_type;
+ typedef typename T::off_type off_type;
+ typedef typename T::pos_type pos_type;
+
+private:
+ char_type p[2];
+
+public:
+ fail_buf()
+ {
+ p[0] = char_type('s');
+ p[1] = char_type();
+ this->setg(p, p, p + 1);
+ }
+
+ virtual int_type underflow()
+ {
+ throw underflow_error();
+ return int_type();
+ }
+
+ virtual int_type uflow()
+ {
+ throw underflow_error();
+ return int_type();
+ }
+
+ virtual int_type
+ overflow(int_type)
+ {
+ throw overflow_error();
+ return int_type();
+ }
+
+ virtual pos_type
+ seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode)
+ {
+ throw positioning_error();
+ return pos_type(off_type(-1));
+ }
+
+ virtual pos_type
+ seekpos(pos_type, std::ios_base::openmode)
+ {
+ throw positioning_error();
+ return pos_type(off_type(-1));
+ }
+
+ virtual int
+ sync()
+ {
+ throw positioning_error();
+ return 0;
+ }
+};
+
+typedef fail_buf<std::streambuf> fail_streambuf;
+std::streambuf* g_buf_to_restore;
+
+// Test that there is an active exception when we reach the terminate handler.
+void my_term()
+{
+ std::cerr.rdbuf(g_buf_to_restore); // be nice, restore the buf of a global
stream
+ try { throw; }
+ catch(const underflow_error&) { std::exit(0); }
+ catch(const overflow_error&) { std::exit(0); }
+ catch(const positioning_error&) { std::exit(0); }
+}
+
+
+
+void f(int x) pre(x >= 0)
+{
+ try{
+ int i = 1;
+ }
+ catch(...) {
+ }
+}
+
+int main()
+{
+ std::set_terminate (my_term);
+ fail_streambuf buf;
+ g_buf_to_restore = std::cerr.rdbuf(&buf);
+ std::cerr.exceptions(std::ios::badbit | std::ios::failbit |
std::ios::eofbit);
+ try
+ {
+ f(-42);
+ } catch (...) {
+ }
+ // We should not get here
+ return 1;
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept2.C
new file mode 100644
index 00000000000..dbb09e89784
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contract-violation-noexcept2.C
@@ -0,0 +1,38 @@
+// test that a noexcept function can't throw even if a violation handler throws
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+// { dg-additional-sources "throwing-violation-handler.cc" }
+
+#include <exception>
+
+void f(int x) noexcept pre(x >= 0)
+{
+}
+
+void g();
+
+bool f_result = true;
+
+void my_term()
+{
+ try { throw; }
+ catch(int) { __builtin_exit(0); }
+}
+
+
+int main()
+{
+ std::set_terminate (my_term);
+ try
+ {
+ g();
+ } catch (...) {
+ // We should not get here
+ __builtin_abort();
+ }
+ if (!f_result)
+ // We should not get here
+ __builtin_abort();
+ // We should not get here
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contract_genericize.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contract_genericize.C
new file mode 100644
index 00000000000..2d0ebc4babd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contract_genericize.C
@@ -0,0 +1,49 @@
+// Check that we do not get a crash
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=enforce" }
+
+
+struct Swapper {
+ static unsigned int swapBytes();
+ static bool isFinished();
+};
+
+
+struct Capacity {
+ Capacity(int capacity);
+ bool operator<( int rhs) const;
+ bool operator>=(int rhs) const;
+};
+
+template <class CAPACITY, class SWAPPER>
+struct Utf32ToUtf8Translator {
+
+ CAPACITY d_capacity;
+
+ Utf32ToUtf8Translator();
+
+ static void translate();
+};
+
+template <class CAPACITY,class SWAPPER>
+void Utf32ToUtf8Translator<CAPACITY, SWAPPER>::translate()
+{
+ Utf32ToUtf8Translator<CAPACITY, SWAPPER> translator;
+
+ unsigned int uc =0;
+ while (!SWAPPER::isFinished()) {
+ uc = SWAPPER::swapBytes();
+ if (0 != uc) {
+ }
+ }
+ contract_assert( translator.d_capacity >= 1 );
+
+}
+
+void func()
+{
+ typedef Utf32ToUtf8Translator<Capacity,
+ Swapper> SwapTranslator;
+
+ SwapTranslator::translate();
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contracts-friend1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-friend1.C
new file mode 100644
index 00000000000..110168584b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-friend1.C
@@ -0,0 +1,36 @@
+// ensure contracts on friend declarations are a complete class context
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+
+
+struct X {
+ friend void fn0(X x) pre (x.a > 0) { }
+
+ static void fns0(X x) pre ( x.a > 0 ) { }
+ static void fns1(X x) pre ( x.a > 0 );
+ static void fns2(X x) pre ( x.a > 0 );
+
+ friend void fn(X &x) { x.a = -5; }
+
+private:
+ int a{10};
+};
+void X::fns1(X x) { }
+void X::fns2(X x) pre ( x.a > 0 ) { }
+
+int main(int, char**) {
+ X x;
+ fn(x); // no contract
+
+ fn0(x);
+
+ X::fns0(x);
+ X::fns1(x);
+ X::fns2(x);
+ return 0;
+}
+
+// { dg-output "contract violation in function void fn0.X. at .*.C:7:
.*(\n|\r\n|\r)" }
+// { dg-output "contract violation in function static void X::fns0.X. at
.*.C:9: .*(\n|\r\n|\r)" }
+// { dg-output "contract violation in function static void X::fns1.X. at
.*.C:10: .*(\n|\r\n|\r)" }
+// { dg-output "contract violation in function static void X::fns2.X. at
.*.C:19: .*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class1.C
new file mode 100644
index 00000000000..4dd9c9deb64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class1.C
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+void gfn3(int n) pre ( n > 0 );
+
+struct Outer {
+ struct Inner {
+ void fn(int n) pre ( n > 0 && bob > 1 );
+ void fn2(int n) pre ( n > 0 && bob > 1 );
+ };
+
+ void fn(int m) pre (m > 1 );
+ friend void Inner::fn(int n) pre ( n > 0 && bob > 1 ); // { dg-error "not
declared" }
+
+ friend void gfn(int p) pre ( p > 0 );
+ friend void gfn(int q) pre ( q > 1 );
+
+ friend void gfn2(int q);
+ friend void gfn2(int p) pre ( p > 0 ) { } // { dg-error "declaration adds
contracts" }
+
+ static int bob;
+};
+int Outer::bob{-1};
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class2.C
new file mode 100644
index 00000000000..8de3005b100
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-nested-class2.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+
+void gfn3(int n) pre (n > 0 );
+
+struct Outer {
+ struct Inner {
+ void fn(int n) pre (n > 0 && bob > 1);
+ };
+
+ void fn(int m) pre (m > 1);
+
+ friend void gfn1(int p) pre (p > 0) { }
+
+ friend void gfn2(int p, Outer *) pre (p > 0) { }
+
+ friend void gfn3(int n);
+
+ static int bob;
+};
+int Outer::bob{-1};
+
+void Outer::Inner::fn(int x) { }
+void Outer::fn(int y) { }
+
+void gfn3(int n) { }
+void gfn1(int q);
+
+int main(int, char **) {
+ Outer::Inner in;
+ in.fn(-5);
+ Outer out;
+ out.fn(-6);
+ gfn1(-7);
+ gfn2(-8, &out);
+ gfn3(-9);
+}
+
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contracts-tmpl-spec2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-tmpl-spec2.C
new file mode 100644
index 00000000000..3137306ae50
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-tmpl-spec2.C
@@ -0,0 +1,446 @@
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
-fsigned-char" }
+#include <cstdio>
+
+// template specializations can have differing contracts
+template<typename T>
+int body(int a)
+ pre ( a > 0 )
+{
+ T t = a * 2.5;
+ return t;
+}
+
+template<>
+int body<double>(int a)
+ pre ( a > 1 )
+{
+ double t = a * 3.3;
+ return t;
+}
+
+template<typename T>
+int none(int a)
+ pre ( a > 0 )
+{
+ return -a;
+}
+
+template<>
+int none<double>(int a)
+ pre ( a > 1 )
+{
+ return a - 100;
+}
+
+template<typename T>
+int arg0(T t)
+ pre ( t > 0 )
+{
+ return -t - 10;
+}
+
+template<>
+int arg0<double>(double t)
+ pre ( t > 1 )
+{
+ return -t + 10;
+}
+
+template<typename T>
+int arg1(int a, T t)
+ pre ( a > 0 )
+ pre ( t > 0 )
+{
+ return -t * a;
+}
+
+template<>
+int arg1<double>(int a, double t)
+ pre ( a > 1 )
+ pre ( t > 1 )
+{
+ return -t * a + 17;
+}
+
+template<typename T>
+T ret(int a)
+ pre ( a > 0 )
+{
+ return -a;
+}
+
+template<>
+double ret<double>(int a)
+ pre ( a > 1 )
+{
+ return -a * 3.3;
+}
+
+// template specializations can have no contracts
+template<typename T>
+int g1(T t) pre ( t > 0 )
+{
+ return (int)t;
+}
+
+template<>
+int g1<double>(double t)
+{
+ return (int)t;
+}
+
+// template specializations can have no contracts in the first decl but add
+// them later
+template<typename T>
+int g2(T t) pre ( t > 0 )
+{
+ return (int)t;
+}
+
+template<>
+int g2<double>(double t);
+
+template<>
+int g2<double>(double t)
+ pre ( t < 0 )
+{
+ return (int)t;
+}
+
+template<>
+int g2<char>(char t)
+ pre ( t < 'c' )
+{
+ return (int)t;
+}
+
+// contracts can be different on the general template, partial and full specs
+template<typename T, typename S>
+struct G3
+{
+ void f(T t, S s)
+ pre ( t > 0 )
+ pre ( s > 0 )
+ {
+ printf ("G3 general T S\n");
+ }
+};
+
+template<typename S>
+struct G3<int, S>
+{
+ void f(int t, S s) pre ( t > 1 ) pre ( s > 1 ) ;
+};
+
+template<typename S>
+void G3<int, S>::f(int t, S s)
+ pre ( t > 1 )
+ pre ( s > 1 )
+{
+ printf ("G3 partial int S\n");
+}
+
+template<>
+void G3<int, double>::f(int t, double s)
+ pre ( t > 2 )
+ pre ( s > 2 )
+{
+ printf ("G3 full int double\n");
+}
+
+struct C
+{
+ bool operator>(int rhs) { return false; }
+};
+
+// deletes contracts
+template<>
+void G3<int, C>::f(int t, C s);
+
+template<>
+void G3<int, C>::f(int t, C s)
+{
+ printf ("G3 full int C\n");
+};
+
+// specialized ctors
+template<typename T, typename S>
+struct G4
+{
+ G4(T t, S s)
+ pre ( t > 0 )
+ pre ( s > 0 )
+ post ( x > 0 )
+ {
+ printf ("G4 general T S\n");
+ return;
+ }
+ int x{-1};
+};
+
+template<typename S>
+struct G4<char, S>
+{
+ G4(char t, S s)
+ pre ( t > 'c' )
+ pre ( s > 3 )
+ post ( x2 > 3 )
+ {
+ printf ("G4 partial char S\n");
+ return;
+ }
+ int x2{-1};
+};
+
+template<>
+G4<double, double>::G4(double, double)
+{
+ printf ("G4 full double double\n");
+ return;
+}
+
+template<>
+G4<double, char>::G4(double a, char b)
+ pre ( a > 0 )
+ pre ( b > 'b' )
+ post ( x > 1 )
+{
+ printf ("G4 full double char\n");
+ return;
+}
+
+// crossover of template classes and template members ok
+template<typename T, typename S>
+struct G5
+{
+ template<typename P>
+ void f(T t, S s, P r)
+ pre ( t > 0 )
+ pre ( s > 0 )
+ pre ( r > 0 )
+ {
+ printf ("G5 gen T S, f gen R\n");
+ }
+};
+
+template<typename S>
+struct G5<char, S>
+{
+ template<typename R>
+ void f(char x, S y, R z)
+ pre ( x > 'z' )
+ pre ( y > 1 )
+ pre ( z > 1 )
+ {
+ printf ("G5 partial char S, f gen R\n");
+ }
+};
+
+template<>
+template<typename Q>
+void G5<double, double>::f(double a, double b, Q c)
+ pre ( a > 2 )
+ pre ( b > 2 )
+ pre ( c > 2 )
+{
+ printf ("G5 full double double, f gen R\n");
+}
+
+int main(int, char**)
+{
+ printf("%d\n", body<int>(-1));
+ printf("%d\n", body<double>(-1));
+ printf("%d\n", none<int>(-1));
+ printf("%d\n", none<double>(-1));
+ printf("%d\n", arg0(-1));
+ printf("%d\n", arg0(-1.0));
+ printf("%d\n", arg1(-3, -1));
+ printf("%d\n", arg1(-3, -1.0));
+ printf("%d\n", (int)ret<int>(-1));
+ printf("%d\n", (int)ret<double>(-1));
+ printf("%f\n", ret<double>(-1));
+
+ printf("%d\n", g1(-1));
+ printf("%d\n", g1(-1.0));
+
+ printf("%d\n", g2(-1));
+ printf("%d\n", g2(1.0));
+ printf("%d\n", g2('d'));
+
+ G3<double, double> g3_gen;
+ G3<int, int> g3_partial;
+ G3<int, double> g3_full;
+ g3_gen.f(-1.0, -1.0); // general
+ g3_partial.f(-2, -2); // partial spec
+ g3_full.f(-3, -3.0); // full spec
+
+ G3<char, char> g3_gen2;
+ G3<int, char> g3_partial2;
+ g3_gen2.f((char)-1, (char)-1);
+ g3_partial2.f(-1, (char)-1);
+
+ G3<int, C> g3_full2;
+ g3_full2.f(5, C{});
+ g3_full2.f(-5, C{});
+
+ G4 g4_gen{-1, -1};
+ G4 g4_full1{-1.0, -1.0};
+ G4 g4_full2{-1.0, (char)'b'};
+ G4 g4_partial{(char)'c', -5};
+
+ G5<int, int> g5_gen;
+ g5_gen.f(-1, -1, -2);
+ g5_gen.f(-1, -1, -2.0);
+
+ G5<char, int> g5_part;
+ g5_part.f('a', -1, -2);
+ g5_part.f('a', -1, -2.1);
+
+ G5<double, double> g5_full;
+ g5_full.f(-1.0, -1.0, -2);
+ g5_full.f(-1.0, -1.0, -2.1);
+ return 0;
+}
+
+// { dg-output {contract violation in function int body.int. .with T = int. at
.*:9: a > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-2(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int body.int. .with T = double.
at .*:17: a > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-3(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int none.int. .with T = int. at
.*:25: a > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {1(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int none.int. .with T = double.
at .*:32: a > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-101(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int arg0.T. .with T = int. at
.*:39: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-9(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int arg0.T. .with T = double.
at .*:46: t > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {11(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int arg1.int, T. .with T = int.
at .*:53: a > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function int arg1.int, T. .with T = int.
at .*:54: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-3(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int arg1.int, T. .with T =
double. at .*:61: a > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function int arg1.int, T. .with T =
double. at .*:62: t > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {14(\n|\r\n|\r)} }
+// { dg-output {contract violation in function T ret.int. .with T = int. at
.*:69: a > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {1(\n|\r\n|\r)} }
+// { dg-output {contract violation in function T ret.int. .with T = double. at
.*:76: a > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {3(\n|\r\n|\r)} }
+// { dg-output {contract violation in function T ret.int. .with T = double. at
.*:76: a > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {3.300000(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int g1.T. .with T = int. at
.*:83: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-1(\n|\r\n|\r)} }
+// { dg-output {-1(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int g2.T. .with T = int. at
.*:97: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {-1(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int g2.T. .with T = double. at
.*:107: t < 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {1(\n|\r\n|\r)} }
+// { dg-output {contract violation in function int g2.T. .with T = char. at
.*:114: t < 'c'(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {100(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G3<T, S>::f.T, S. .with T
= double; S = double. at .*:124: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G3<T, S>::f.T, S. .with T
= double; S = double. at .*:125: s > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G3 general T S(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = int. at .*:139: t > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = int. at .*:140: s > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G3 partial int S(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = double. at .*:147: t > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = double. at .*:148: s > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G3 full int double(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G3<T, S>::f.T, S. .with T
= char; S = char. at .*:124: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G3<T, S>::f.T, S. .with T
= char; S = char. at .*:125: s > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G3 general T S(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = char. at .*:139: t > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G3<int, S>::f.int, S.
.with S = char. at .*:140: s > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G3 partial int S(\n|\r\n|\r)} }
+// { dg-output {G3 full int C(\n|\r\n|\r)} }
+// { dg-output {G3 full int C(\n|\r\n|\r)} }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
int; S = int. at .*:173: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
int; S = int. at .*:174: s > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G4 general T S(\n|\r\n|\r)} }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
int; S = int. at .*:175: x > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: post, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G4 full double double(\n|\r\n|\r)} }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
double; S = char. at .*:206: a > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
double; S = char. at .*:207: b > 'b'(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G4 full double char(\n|\r\n|\r)} }
+// { dg-output {contract violation in function G4<T, S>::G4.T, S. .with T =
double; S = char. at .*:208: x > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: post, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function G4<char, S>::G4.char, S. .with
S = int. at .*:187: t > 'c'(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function G4<char, S>::G4.char, S. .with
S = int. at .*:188: s > 3(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G4 partial char S(\n|\r\n|\r)} }
+// { dg-output {contract violation in function G4<char, S>::G4.char, S. .with
S = int. at .*:189: x2 > 3(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: post, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = int; S = int. at .*:220: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = int; S = int. at .*:221: s > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = int; S = int. at .*:222: r > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 gen T S, f gen R(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = int; S = int. at .*:220: t > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = int; S = int. at .*:221: s > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = int; S = int. at .*:222: r > 0(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 gen T S, f gen R(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = int; S = int. at .*:233: x > 'z'(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = int; S = int. at .*:234: y > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = int; S = int. at .*:235: z > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 partial char S, f gen R(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = double; S = int. at .*:233: x > 'z'(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = double; S = int. at .*:234: y > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<char, S>::f.char, S, R.
.with R = double; S = int. at .*:235: z > 1(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 partial char S, f gen R(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = double; S = double. at .*:244: a > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = double; S = double. at .*:245: b > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = int; T = double; S = double. at .*:246: c > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 full double double, f gen R(\n|\r\n|\r)} }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = double; S = double. at .*:244: a > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = double; S = double. at .*:245: b > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {contract violation in function void G5<T, S>::f.T, S, P. .with
P = double; T = double; S = double. at .*:246: c > 2(\n|\r\n|\r)} }
+// { dg-output ".assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no.(\n|\r\n|\r)" }
+// { dg-output {G5 full double double, f gen R(\n|\r\n|\r)} }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p4.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p4.C
new file mode 100644
index 00000000000..0ce31b65b35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p4.C
@@ -0,0 +1,126 @@
+// N5008 :
+// A declaration D of a function or function template f that is not a first
declaration shall have either no
+// function-contract-specifier-seq or the same function-contract-specifier-seq
(see below) as any first declaration
+// F reachable from D.
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+// allowed to repeat contracts or omit them
+int g0(int a) pre (a > 0);
+int g0(int a) pre (a > 0 );
+int g0(int a) pre (a > 0);
+
+int g1(int a) pre (a > 0);
+int g1(int a);
+
+int g2(int a);
+int g2(int a) pre (a > 0); // { dg-error "declaration adds contracts" }
+
+struct G0
+{
+ int f(int a);
+};
+
+int G0::f(int a) pre (a > 0) // { dg-error "declaration adds contracts" }
+{
+ return -a;
+}
+
+struct G1
+{
+ int f(int a)
+ pre (a > 0);
+};
+
+int G1::f(int a)
+ pre ( a > 0 ) // OK. same as the first decl.
+{ return 0; }
+
+int G1::f(int a); // OK not adding
+
+int G1::f(int a) // { dg-error "different number of contracts" }
+ pre ( a > 0 ) pre ( a > 0 );
+
+int f0(int a)
+ pre ( a > 0 );
+
+int f0(int a) // { dg-error "different number of contracts" }
+ pre ( a > 0 ) pre ( a > 10 );
+
+int f1(int a)
+ pre ( a > 0 );
+int f1(int a)
+ pre ( a < 0 ); // { dg-error "mismatched contract" }
+
+struct Base
+{
+ virtual int f(int a) // { dg-error "contracts cannot be added to virtual
functions" }
+ pre (a > 0);
+};
+
+struct Child : Base
+{
+ int f(int a) // { dg-error "contracts cannot be added to virtual functions" }
+ pre (a < 0);
+};
+
+struct F1
+{
+ virtual int f(int a);
+};
+
+int F1::f(int a) // { dg-error "declaration adds contracts" }
+ pre (a > 0)
+{
+ return -a;
+}
+
+
+struct T1
+{
+ void vfun(int m, double n);
+};
+
+void T1::vfun(int m, double n)
+ pre ( x < 0 ) // { dg-error "was not declared in this" }
+{
+}
+
+void T1::vfun(int m, double n) // { dg-error "declaration adds contracts" }
+ pre(true);
+
+struct Foo {
+ virtual void f10 (int) // { dg-error "contracts cannot be added to virtual
functions" }
+ pre ( false ) {}
+};
+
+struct Bar : Foo {
+ void f10 (int n = 0) override // { dg-error "contracts cannot be added to
virtual functions" }
+ pre ( false );
+};
+
+// we currently don't diagnose an error here if the original contract was
erroneous.
+void Bar::f10(int n)
+ pre (n >10) {}; // { dg-error "mismatched contract" }
+
+
+struct NonTrivial{
+ NonTrivial(){};
+ NonTrivial(const NonTrivial&){}
+ ~NonTrivial(){};
+ int x = 0;
+};
+
+void f(const NonTrivial s) pre(s.x >0);
+void f(const NonTrivial g) {};
+void f(const NonTrivial t) pre(t.x >0);
+
+double sqrt(const double x)
+ post( r : r >= 0 );
+
+
+double sqrt(const double x)
+ post( r : r >= 0)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p6.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p6.C
new file mode 100644
index 00000000000..3f845216b56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.func.p6.C
@@ -0,0 +1,21 @@
+// N5008:
+// dcl.contract.func/p6
+// A virtual function (11.7.3),
+// TODO : a deleted function (9.6.3), or a function defaulted on its first
declaration (9.6.2)
+// shall not have a function-contract-specifier-seq.
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+struct Base
+{
+ virtual int f1() pre(true); // { dg-error "contracts cannot be added to
virtual functions" }
+ virtual int f2();
+
+};
+struct Child : Base
+{
+ int f2() pre(true); // { dg-error "contracts cannot be added to virtual
functions" }
+
+};
+
+
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1-NT.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1-NT.C
new file mode 100644
index 00000000000..5cbfb611758
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1-NT.C
@@ -0,0 +1,146 @@
+// N5008 :
+// dcl.contract.res/p1
+// The result-name-introducer of a postcondition-specifier is a declaration.
The result-name-introducer introduces
+// the identifier as the name of a result binding of the associated function.
If a postcondition assertion has a
+// result-name-introducer and the return type of the function is cv void, the
program is ill-formed.
+//
+// Various tests with non trivial return value identifier
+//
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+
+struct NonTrivial{
+ NonTrivial(){};
+ NonTrivial(const NonTrivial&){}
+ ~NonTrivial(){};
+ int x = 0;
+};
+
+template<typename T>
+bool check(T t){
+ return true;
+}
+struct S{
+ NonTrivial f1(const NonTrivial i) post(r: i.x > 0 ) { return NonTrivial{};}
+
+ template <typename T>
+ NonTrivial f2(const T i) post(r: i.x > 0 ) { return NonTrivial{};}
+
+ auto f3(const NonTrivial i) post(r: i.x > 0 ) { return NonTrivial{};}
+
+ template <typename T>
+ T f4(const T i) post(r: i.x > 0 ) { return NonTrivial{};}
+
+ template <typename T>
+ auto f5(const T i) post(r: i.x > 0 ) { return i;}
+
+ template <typename T>
+ auto f6(const T i) post(r: check(i) ) { return i;}
+
+ auto f7(const NonTrivial i) post(r: check(r) ) { return i;}
+
+};
+
+template <typename U>
+struct S1
+{
+
+ struct S2
+ {
+ NonTrivial
+ f1 (const NonTrivial i) post(r: i.x > 0 )
+ { return NonTrivial
+ {};
+ }
+
+ template <typename T>
+ NonTrivial
+ f2 (const T i) post(r: i.x > 0 )
+ { return NonTrivial
+ {};
+ }
+
+ auto
+ f3 (const NonTrivial i)
+ post(r: i.x > 0 )
+ { return NonTrivial
+ {};}
+
+ template <typename T>
+ T
+ f4 (const T i)
+ post(r: i.x > 0 )
+ { return NonTrivial
+ {};}
+
+ template <typename T>
+ auto
+ f5 (const T i)
+ post(r: i.x > 0 )
+ { return i;}
+
+ };
+
+ NonTrivial
+ f1 (const NonTrivial i)
+ post(r: i.x > 0 )
+ { S2 s;
+ return s.f1(i);
+ }
+
+ template <typename T>
+ NonTrivial
+ f2 (const T i)
+ post(r: i.x > 0 )
+ { S2 s;
+ return s.f2(i);
+ }
+
+ auto
+ f3 (const NonTrivial i)
+ post(r: i.x > 0 )
+ { S2 s;
+ return s.f3(i);
+ }
+
+ template <typename T>
+ T
+ f4 (const T i)
+ post(r: i.x > 0 )
+ { S2 s;
+ return s.f4(i);
+ }
+
+ template <typename T>
+ auto
+ f5 (const T i)
+ post(r: i.x > 0 )
+ { S2 s;
+ return s.f5(i);
+ }
+
+ };
+
+
+int main()
+{
+ S s;
+ NonTrivial n;
+ s.f1(NonTrivial{});
+
+ s.f2(n);
+ s.f3(n);
+ s.f4(n);
+ s.f5(n);
+ s.f6(n);
+ s.f7(n);
+
+
+ S1<NonTrivial> s1;
+ s1.f1(n);
+ s1.f2(n);
+ s1.f3(n);
+ s1.f4(n);
+ s1.f5(n);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1.C
new file mode 100644
index 00000000000..935f32b1a2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p1.C
@@ -0,0 +1,21 @@
+// N5008 :
+// dcl.contract.res/p1
+// The result-name-introducer of a postcondition-specifier is a declaration.
The result-name-introducer introduces
+// the identifier as the name of a result binding of the associated function.
If a postcondition assertion has a
+// result-name-introducer and the return type of the function is cv void, the
program is ill-formed.
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+
+void f(const int i) post (r: i > 2); // { dg-error "function does not return a
value to test" }
+
+template <typename T>
+void g() post (r: true ); // { dg-error "function does not return a value to
test" }
+
+
+struct S{
+
+ S() post (r : true); // { dg-error "does not return a value to test" }
+ void f(const int i) post (r: i > 2); // { dg-error "function does not return
a value to test" }
+ ~S() post (r : true); // { dg-error "does not return a value to test" }
+};
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p2.C
new file mode 100644
index 00000000000..326ede4d024
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dcl.contract.res.p2.C
@@ -0,0 +1,25 @@
+// N5008 :
+// dcl.contract.res/p2
+// When the declared return type of a non-templated function contains a
placeholder type, a postcondition-
+// specifier with a result-name-introducer shall be present only on a
definition.
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+
+auto no_deduced_res_types_on_non_defs (int x) // { dg-error "postconditions
with deduced result name types must only appear on function definitions" }
+ pre (x > 1)
+ post (r: r > 17);
+
+// =====
+
+auto g(auto&)
+post (r: r >= 0); // OK, g is a template.
+
+auto f2() post (r : r > 0) // OK, type of r is deduced below.
+{ return 5; }
+
+template <typename T>
+auto f3 () post (r: r > 0); // OK, postcondition instantiated with template
+
+auto f4 () post (true); // OK, return value not named
+
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/debug-and-opt.C
b/gcc/testsuite/g++.dg/contracts/cpp26/debug-and-opt.C
new file mode 100644
index 00000000000..0d6fa197895
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/debug-and-opt.C
@@ -0,0 +1,15 @@
+// Check that we do not ICE with debug + optimisation.
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
-O -g" }
+
+
+int foo (const int i)
+ pre (i > 3)
+{
+ return i;
+}
+
+int main()
+{
+ foo (1);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/deferred1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/deferred1.C
new file mode 100644
index 00000000000..165f8eded78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/deferred1.C
@@ -0,0 +1,49 @@
+// This case should be diagnosed, but we do not handl deferred contracts
properly at the moment.
+// For now, diagnose that we at least don't accidentally merge the contracts
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -g3" }
+#include <cassert>
+struct contract
+{
+ int checked = 0;
+};
+
+contract a, b;
+
+bool
+checkA ()
+{
+ a.checked++;
+ return true;
+}
+
+bool
+checkB ()
+{
+ b.checked++;
+ return true;
+}
+
+void
+clear_checks ()
+{
+ a.checked = b.checked = 0;
+
+}
+
+struct S
+{
+ friend int f1(S) post (checkB());
+ friend int f1(S) pre (checkA()){ return 1;};
+};
+
+
+int main()
+{
+ S s;
+
+ clear_checks ();
+ f1(s);
+ assert (a.checked > 0);
+ assert (b.checked == 0);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/dependent_contract.C
b/gcc/testsuite/g++.dg/contracts/cpp26/dependent_contract.C
new file mode 100644
index 00000000000..e4f35c13b8d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/dependent_contract.C
@@ -0,0 +1,32 @@
+// check that dependent contract check does not cause an ICE
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+template <typename ST>
+struct S{
+
+ int* check() const
+ {
+ static int i = 6;
+ return &i;
+ }
+
+ template <typename T>
+ T* tcheck(T) const{
+ static T t;
+ return nullptr;
+ }
+
+ void f() pre(check()) pre(tcheck(1)){
+ }
+
+ template <typename T>
+ void f(T t) pre(check()) pre(tcheck(1)) pre(tcheck<T>(t)){
+ }
+
+};
+
+int main() {
+ S<int> s;
+ s.f();
+ s.f(1);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/empty-nt-param.C
b/gcc/testsuite/g++.dg/contracts/cpp26/empty-nt-param.C
new file mode 100644
index 00000000000..8ac0d41e0f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/empty-nt-param.C
@@ -0,0 +1,42 @@
+// check that we do not ICE with an empty nontrivial parameter
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+struct NTClass {
+ NTClass(){};
+ NTClass(const NTClass&){}
+ ~NTClass(){};
+};
+
+struct Empty {};
+
+void f (const NTClass i) pre (true){
+}
+
+void g (const Empty i) pre (true){
+}
+
+
+struct S {
+ void f (const NTClass i)
+ post ( true);
+
+ void g (const Empty i)
+ post ( true);
+
+};
+
+void
+S::f (NTClass i){}
+
+void
+S::g (Empty i){}
+
+int main(){
+
+ NTClass n;
+ f(n);
+ g(Empty{});
+
+
+}
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq-error.C
b/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq-error.C
new file mode 100644
index 00000000000..06433fce899
--- /dev/null
+++
b/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq-error.C
@@ -0,0 +1,50 @@
+// generic function-contract-specifier-seq parsing checks
+// N5008
+// function-contract-specifier-seq :
+// function-contract-specifier function-contract-specifier-seq opt
+// function-contract-specifier :
+// precondition-specifier
+// postcondition-specifier
+// precondition-specifier : pre attribute-specifier-seq opt (
conditional-expression )
+// postcondition-specifier :
+// post attribute-specifier-seq opt ( result-name-introducer opt
conditional-expression )
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+int f(int);
+int g1(int a) pre(f(a) > a) pre (true) post(false) pre(f(1) > 4)
+{
+ int r = a - f(a);
+ return 2 * r;
+}
+
+int fun(int n) pre (n > 0 );
+void fun2(int n) pre n > 0 ; // { dg-error {expected '\(' before } }
+ // { dg-error {expected '\)' before ';' token} "" { target *-*-* } .-1 }
+void fun2(int n) pre (: n > 0 ]]; // { dg-error }
+
+int main()
+{
+ int x;
+
+ contract_assert ( x >= 0 );
+
+ contract_assert ( x > 0 ? true : false );
+ contract_assert ( x < 0 ? true : false );
+
+ contract_assert ( x = 0 ); // { dg-error {expected '\)' before '=' token} }
+ // { dg-error {expected .;. before '=' token} "" { target *-*-* } .-1 }
+ // { dg-error {expected primary-expression before '=' token} "" { target
*-*-* } .-2 }
+
+ contract_assert ( y == 0 ); // { dg-error ".y. was not declared in this
scope" }
+
+ return 0;
+}
+
+struct Baz
+{
+ void f(int x) pre(x = 0); // { dg-error "expected conditional-expression" }
+ void g(int x) pre(x, x); // { dg-error "expected conditional-expression" }
+ void h(const int x) post(x = 0); // { dg-error "expected
conditional-expression" }
+ void i(const int x) post(x, x); // { dg-error "expected
conditional-expression" }
+};
diff --git
a/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq.C
b/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq.C
new file mode 100644
index 00000000000..51560268f23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/function-contract-specifier-seq.C
@@ -0,0 +1,122 @@
+// generic function-contract-specifier-seq parsing checks
+// N5008
+// function-contract-specifier-seq :
+// function-contract-specifier function-contract-specifier-seq opt
+// function-contract-specifier :
+// precondition-specifier
+// postcondition-specifier
+// precondition-specifier : pre attribute-specifier-seq opt (
conditional-expression )
+// postcondition-specifier :
+// post attribute-specifier-seq opt ( result-name-introducer opt
conditional-expression )
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+// { dg-additional-options "-fcontracts" }
+
+static_assert (__cpp_contracts >= 202502L);
+
+void f(int i) pre (i>3);
+
+int g(int j) post (r:r>4) pre (j !=0);
+
+namespace parsing_basic_test {
+ int f(const int x)
+ pre (x >= 0)
+ post (r: r > x); // r is the return value
+
+ struct A {
+ bool empty() const noexcept;
+ void clear()
+ post (empty()); // return value is optional
+ };
+}
+
+namespace parsing_trailing_return_type_test {
+ auto f() -> int pre(true);
+
+ struct S1 {
+ auto g() const & noexcept -> int
+ pre(true);
+ };
+}
+
+
+namespace parsing_lambda_test {
+ auto f1 = [] (int x)
+ pre(x > 0) { return x * x; };
+
+ auto f2 = [] (int x) -> int
+ pre(x > 0) { return x * x; };
+}
+
+namespace parsing_pre_post_names_test {
+ void f(bool pre, bool post)
+ pre(pre) pre(post);
+}
+
+namespace parsing_requires_clause_test {
+ template <typename T> concept C = true;
+
+ template <typename T>
+ auto g(T x) -> bool
+ requires C<T>
+ pre (x > 0);
+}
+
+namespace parsing_ambig1_test {
+ const bool a = true;
+ using pre = int;
+
+ auto f() -> pre pre(a);
+ // pre is the return type, pre(a) the precondition
+}
+
+namespace parsing_ambig2_test {
+ const bool a = true;
+ template <typename T> struct pre {};
+ using post = int;
+
+ auto g() -> pre<post> pre(a);
+ // pre<post> is the return type, pre(a) the precondition
+}
+
+namespace parsing_ambig3_test {
+ constexpr bool a = true;
+ constexpr bool pre(bool) { return true; }
+
+ template <typename T>
+ void f1() requires (pre(a));
+ // just a requires clause, no postcondition
+
+ using b = bool;
+
+ template <typename T>
+ void f2() requires ((b)pre(a));
+ // just a requires clause, no postcondition
+
+ template <typename T>
+ void f3() requires (a) pre(a);
+ // pre(a) is a postcondition
+}
+
+namespace parsing_ambig_test4 {
+ constexpr int a = 1;
+ constexpr int b = 2;
+ constexpr int c = 0;
+ constexpr int pre(int i) { return i; }
+
+ template <typename T>
+ void f() requires (a < b > pre(c));
+ // just a requires clause, no postcondition
+
+ template <typename T> constexpr bool d = true;
+ using e = char;
+
+ template <typename T>
+ void g() requires d < e > pre(c);
+ // d<e> is a bool variable template, pre(c) is the precondition
+
+
+ template <typename T>
+ void f() requires (a < b > pre(c));
+ // just a requires clause, no postcondition
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/lambda.C
b/gcc/testsuite/g++.dg/contracts/cpp26/lambda.C
new file mode 100644
index 00000000000..747e325ce93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/lambda.C
@@ -0,0 +1,5 @@
+// check that we do not crash when capturing a constified entity in a contract
assertion lambda
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+void f(int i, int j) pre( [i, &j](){ return true;} ( ))
+{}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/name_mangling.C
b/gcc/testsuite/g++.dg/contracts/cpp26/name_mangling.C
new file mode 100644
index 00000000000..1e81c1247a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/name_mangling.C
@@ -0,0 +1,15 @@
+// check that we do not have conflicts with post condition that includes a
return value
+// identifier and post condition on an identically named void function with the
+// additional parameter that matches the returen value of the first function
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+
+int f() post(r:r>1){ return 2;}
+void f(int i) post(true){ }
+
+int main() {
+
+ f();
+ f(2);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/over.call.func.p3.1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/over.call.func.p3.1.C
new file mode 100644
index 00000000000..381d48d4447
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/over.call.func.p3.1.C
@@ -0,0 +1,36 @@
+// N5008 :
+// [over.call.func/p3.1
+// if the unqualified function call appears in a precondition assertion of a
constructor or a postcondition
+// assertion of a destructor and overload resolution selects a non-static
member function, the call is
+// ill-formed;
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+
+struct S{
+ bool f();
+ bool k;
+ S() pre(&k); // { dg-error "required when accessing a member" }
+ ~S()post(&f()); // { dg-error "required when accessing a member" }
+ S(int i) pre(&(this->k))
+ pre([](){
+ struct SIn{
+ bool i = true;
+ bool f() const pre(i) { return i;}
+ SIn() pre(&i){}; // { dg-error "required when accessing a
member" }
+ ;
+ };
+ SIn sin;
+ return sin.f();
+ }());
+};
+
+struct S2{
+ bool f() const { return true;}
+ bool i = true;
+ bool k = true;
+ S2() pre(&(this->k) != &(this->i)) post(i) {};
+ ~S2() pre(f()){};
+};
+int main()
+{
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/pr113968.C
b/gcc/testsuite/g++.dg/contracts/cpp26/pr113968.C
new file mode 100644
index 00000000000..bd03da4fce7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr113968.C
@@ -0,0 +1,23 @@
+// check that an invalid contract condition doesn't cause an ICE
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts" }
+struct A {
+ A(A &);
+};
+struct S{
+ void f(A a) pre(a) // { dg-error "could not convert" }
+ pre(a.b) // { dg-error "has no member" }
+ {
+
+ }
+};
+void f(A a) pre(a) // { dg-error "could not convert" }
+ pre(a.b) // { dg-error "has no member" }
+ {
+ contract_assert(a); // { dg-error "could not convert" }
+ contract_assert(a.b); // { dg-error "has no member" }
+}
+
+int main()
+{
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-0.C
b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-0.C
new file mode 100644
index 00000000000..025a8fac459
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-0.C
@@ -0,0 +1,18 @@
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+// Test source location without including <source_location>
+
+int
+foo (int x)
+ pre ( x > 10 )
+{
+ return x - 9;
+}
+
+int main ()
+{
+ foo (9);
+}
+
+// { dg-output "contract violation in function int foo.int. at .*:8: x >
10.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-1.C
b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-1.C
new file mode 100644
index 00000000000..0987d0e62dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-1.C
@@ -0,0 +1,18 @@
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+// Test source location with #include <source_location>
+#include <source_location>
+
+int
+foo (int x)
+ pre ( x > 10 )
+{
+ return x - 9;
+}
+
+int main ()
+{
+ foo (9);
+}
+
+// { dg-output "contract violation in function int foo.int. at .*:8: x >
10.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-2.C
b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-2.C
new file mode 100644
index 00000000000..c1ff148f92f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/src-loc-2.C
@@ -0,0 +1,20 @@
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=observe
" }
+
+// Test source location with a late inclusion of <source_location>
+
+int
+foo (int x)
+ pre ( x > 10 )
+{
+ return x - 9;
+}
+
+#include <source_location>
+
+int main ()
+{
+ foo (9);
+}
+
+// { dg-output "contract violation in function int foo.int. at .*:8: x >
10.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/throwing-violation-handler.cc
b/gcc/testsuite/g++.dg/contracts/cpp26/throwing-violation-handler.cc
new file mode 100644
index 00000000000..da0686ebc71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/throwing-violation-handler.cc
@@ -0,0 +1,23 @@
+#include <contracts>
+
+void handle_contract_violation(const std::contracts::contract_violation&)
+{
+ throw 666;
+}
+
+/* ODR hack to the hilt - f is actually noexcept, and has a contract.
+ We do this to avoid the call site knowing that, so that we verify
+ that the function terminates when it calls the throwing handler
+ that we use above. */
+int f(int);
+
+extern bool f_result;
+
+void g()
+{
+ try {
+ f(-42);
+ } catch (...) {
+ f_result = false;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/unused_warning.C
b/gcc/testsuite/g++.dg/contracts/cpp26/unused_warning.C
new file mode 100644
index 00000000000..44d2d9c67bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/unused_warning.C
@@ -0,0 +1,25 @@
+// check that we do not get unused warnings for contract check function
parameters
+// { dg-do compile { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=enforce
-Wall -Wextra" }
+
+struct TimeInterval{
+ int i = 4;
+ void addInterval(int i, int j);
+};
+
+TimeInterval operator-(const TimeInterval& lhs, const TimeInterval& rhs)
+ pre(2 != rhs.i);
+
+inline
+TimeInterval operator-(const TimeInterval& lhs,
+ const TimeInterval& rhs)
+
+{
+ TimeInterval result(lhs);
+ result.addInterval(-rhs.i, -rhs.i);
+ return result;
+}
+
+int main(int, char**) {
+
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/vaargs.C
b/gcc/testsuite/g++.dg/contracts/cpp26/vaargs.C
new file mode 100644
index 00000000000..abb3ded7c07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/vaargs.C
@@ -0,0 +1,35 @@
+// Check contract assertion on a vaarg function
+// { dg-do run { target c++23 } }
+// { dg-additional-options "-fcontracts -fcontract-evaluation-semantic=enforce
" }
+#include <stdio.h>
+#include <stdarg.h>
+int simple_printf(const char* fmt, ...) pre (fmt != 0) post (r: r > 0)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ while (*fmt != '\0') {
+ if (*fmt == 'd') {
+ int i = va_arg(args, int);
+ printf("%d\n", i);
+ } else if (*fmt == 'c') {
+ // A 'char' variable will be promoted to 'int'
+ // A character literal in C is already 'int' by itself
+ int c = va_arg(args, int);
+ printf("%c\n", c);
+ } else if (*fmt == 'f') {
+ double d = va_arg(args, double);
+ printf("%f\n", d);
+ }
+ ++fmt;
+ }
+
+ va_end(args);
+
+ return 6;
+}
+
+int main()
+{
+ simple_printf("dcff", 3, 'a', 1.999, 42.5);
+}
diff --git a/gcc/testsuite/g++.dg/contracts/cpp2a/check-err.C
b/gcc/testsuite/g++.dg/contracts/cpp2a/check-err.C
new file mode 100644
index 00000000000..70cfd5d221e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp2a/check-err.C
@@ -0,0 +1,18 @@
+// test that attribute syntax is no longer recognized
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fcontracts" }
+
+int fun(int n) [[ pre : n > 0 ]]; // { dg-error {expected ']' before ':'
token} }
+// { dg-warning {'pre' attribute directive ignored} "" { target *-*-* } .-1 }
+int fun2(const int n) [[ post : n > 0 ]]; // { dg-error {expected ']' before
':' token} }
+// { dg-warning {'post' attribute directive ignored} "" { target *-*-* } .-1 }
+
+int main()
+{
+ int x;
+
+ [[assert: x >= 0]]; // { dg-error {expected ']' before ':' token} }
+ // { dg-warning {attributes at the beginning of statement are ignored} "" {
target *-*-* } .-1 }
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr110871.C
b/gcc/testsuite/g++.dg/coroutines/pr110871.C
new file mode 100644
index 00000000000..540704cec83
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr110871.C
@@ -0,0 +1,64 @@
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+// { dg-do run }
+// { dg-skip-if "requires hosted libstdc++ for iostream" { ! hostedlib } }
+
+#include <iostream>
+#include <coroutine>
+
+// In order to test the contract violation diagnostic, we have to set
+// -fcontract-continuation-mode=on; this means that the code will emit
+// the message below - but before that the contract should have been checked.
+void process(int from, int to)
+{
+ if (from > to)
+ std::cout << "would have been a disaster!" << std::endl;
+}
+
+template <typename T>
+struct generator
+{
+ struct promise_type
+ {
+ template <typename... Args>
+ promise_type(Args&&... args) {
+ std::cout << "promise init" << std::endl;
+ process(args...);
+ }
+
+ std::suspend_always yield_value(T) { return {}; }
+
+ std::suspend_always initial_suspend() const noexcept { return {}; }
+ std::suspend_never final_suspend() const noexcept { return {}; }
+ void unhandled_exception() noexcept {}
+
+ generator<T> get_return_object() noexcept { return {}; }
+ };
+};
+
+namespace std {
+template <typename T, typename... Args>
+struct coroutine_traits<generator<T>, Args...>
+{
+ using promise_type = typename generator<T>::promise_type;
+};
+
+};
+
+generator<int> seq(int from, int to)
+ pre (from <= to)
+{
+ std::cout << "coro initial" << std::endl;
+ for (int i = from; i <= to; ++i) {
+ co_yield i;
+ std::cout << "coro resumed" << std::endl;
+ }
+}
+
+int main() {
+ std::cout << "main initial" << std::endl;
+ generator<int> s = seq(10, 5);
+ (void)s;
+ std::cout << "main continues" << std::endl;
+}
+
+// { dg-output "contract violation in function generator<int> seq.int, int. at
.*.C:48: from \<= to.*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/g++.dg/coroutines/pr110872.C
b/gcc/testsuite/g++.dg/coroutines/pr110872.C
new file mode 100644
index 00000000000..29cfd0d4c45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr110872.C
@@ -0,0 +1,50 @@
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+// { dg-do run }
+// { dg-skip-if "requires hosted libstdc++ for iostream" { ! hostedlib } }
+
+#include <iostream>
+#include <coroutine>
+
+
+template <typename T>
+struct generator
+{
+ struct promise_type
+ {
+ std::suspend_always yield_value(T) { return {}; }
+
+ std::suspend_always initial_suspend() const noexcept { return {}; }
+ std::suspend_never final_suspend() const noexcept { return {}; }
+ void unhandled_exception() noexcept {}
+
+ generator<T> get_return_object() noexcept { return {}; }
+ };
+
+ bool is_valid() const { return false; }
+};
+
+namespace std {
+template <typename T, typename... Args>
+struct coroutine_traits<generator<T>, Args...>
+{
+ using promise_type = typename generator<T>::promise_type;
+};
+
+};
+
+generator<int> val(int v)
+ post (g: g.is_valid())
+{
+ std::cout << "coro initial" << std::endl;
+ co_yield v;
+ std::cout << "coro resumed" << std::endl;
+}
+
+int main() {
+ std::cout << "main initial" << std::endl;
+ generator<int> s = val(1);
+ (void)s;
+ std::cout << "main continues" << std::endl;
+}
+
+// { dg-output "contract violation in function generator<int> val.int. at
.*.C:36: g.is_valid().*(\n|\r\n|\r)" }
--
2.39.5 (Apple Git-154)