Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking Issue for Contracts #128044

Open
2 of 9 tasks
pnkfelix opened this issue Jul 21, 2024 · 7 comments
Open
2 of 9 tasks

Tracking Issue for Contracts #128044

pnkfelix opened this issue Jul 21, 2024 · 7 comments
Labels
B-experimental Blocker: In-tree experiment; RFC pending, not yet approved or unneeded (requires FCP to stabilize). C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-contracts `#![feature(contracts)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@pnkfelix
Copy link
Member

pnkfelix commented Jul 21, 2024

This is a tracking issue for the MCP "Contracts" (rust-lang/compiler-team#759).
The feature gate for the issue is #![feature(contracts)].

Current (2025-03-20) design doc: https://hackmd.io/@celinaval/B1UEl3tUyl

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Discussion comments will get marked as off-topic or deleted.
Repeated discussions on the tracking issue may lead to the tracking issue getting locked.

Steps

Unresolved Questions

  • Tooling support: How much functionality should be integrated into Rust project provided tooling itself? E.g. should something like miri be exploring fuzzing of data that is fed into functional preconditions as a way to explore state space?
  • Syntax bikesheds galore: Define the exact syntax for contract attributes. Should we separate correctness vs safety conditions?
  • Static vs dynamic semantics: The idealized contract system would allow contracts to inform both static verification and dynamic validation tools. What's the best way to handle conditions that cannot be checked with both semantics.
  • Safety post-obligations: The safety criteria for some unsafe methods is stated as a constraint on how the caller uses the return value from a method. This cannot be expressed as a mere safety::requires form as envisioned above. Should we add something like: #[safety::at_lifetime_end(|output| str::from_utf8(output).is_ok())], which could only be checked in the future, right before the &mut u8 borrow expires? See original MCP for more details
  • Correctness invariants: As mentioned above, there is probably utility in being able to attach invariants to a type that are used for proving functional correctness. But it is not as clear where to establish the points where correctness invariants must be checked. It may make more sense here to use something like refinement types, where explicit method calls (potentially in ghost code) would (re)establish such invariants.
  • Purity: Do contracts need to be pure (i.e. have no non-local side-effects)?
  • Panic: How should a panicking expression within a contract be treated? Should users be able to specify conditions that will lead to panic? Should any post-condition be checked during unwind?

Implementation history

Compiler support

Standard library usage

@pnkfelix pnkfelix added the C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC label Jul 21, 2024
@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. F-contracts `#![feature(contracts)]` labels Aug 5, 2024
@traviscross
Copy link
Contributor

@rustbot labels +T-lang

@rustbot rustbot added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Jan 16, 2025
@traviscross
Copy link
Contributor

traviscross commented Jan 29, 2025

We've approved this as as lang experiment:

@nikomatsakis is serving as the liaison.

jhpratt added a commit to jhpratt/rust that referenced this issue Feb 4, 2025
#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
fmease added a commit to fmease/rust that referenced this issue Feb 5, 2025
#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 5, 2025
Rollup merge of rust-lang#128045 - pnkfelix:rustc-contracts, r=oli-obk

#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
@jieyouxu jieyouxu added the B-experimental Blocker: In-tree experiment; RFC pending, not yet approved or unneeded (requires FCP to stabilize). label Feb 5, 2025
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Feb 6, 2025
#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang/rust#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
flip1995 pushed a commit to flip1995/rust-clippy that referenced this issue Feb 6, 2025
#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang/rust#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
@codeOverFlow

This comment has been minimized.

@traviscross

This comment has been minimized.

@nikomatsakis nikomatsakis moved this to Exploration in Lang team features Feb 21, 2025
@nikomatsakis nikomatsakis moved this from Exploration to Uncategorized in Lang team features Feb 21, 2025
@nikomatsakis nikomatsakis moved this from Needs champion to Exploration in Lang team features Mar 5, 2025
github-actions bot pushed a commit to tautschnig/verify-rust-std that referenced this issue Mar 11, 2025
#[contracts::requires(...)]  + #[contracts::ensures(...)]

cc rust-lang#128044

Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings  that culminates in:
1. a compile-time flag (`-Z contract-checks`) that, similar to `-Z ub-checks`, attempts to ensure that the decision of enabling/disabling contract checks is delayed until the end user program is compiled,
2. invocations of lang-items that handle invoking the precondition,  building a checker for the post-condition, and invoking that post-condition checker at the return sites for the function, and
3. intrinsics for the actual evaluation of pre- and post-condition predicates that third-party verification tools can intercept and reinterpret for their own purposes (e.g. creating shims of behavior that abstract away the function body and replace it solely with the pre- and post-conditions).

Known issues:

 * My original intent, as described in the MCP (rust-lang/compiler-team#759) was   to have a rustc-prefixed attribute namespace (like   rustc_contracts::requires). But I could not get things working when I tried   to do rewriting via a rustc-prefixed builtin attribute-macro. So for now it  is called `contracts::requires`.

 * Our attribute macro machinery does not provide direct support for attribute arguments that are parsed like rust expressions. I spent some time trying to add that (e.g. something that would parse the attribute arguments as an AST while treating the remainder of the items as a token-tree), but its too big a lift for me to undertake. So instead I hacked in something approximating that goal, by semi-trivially desugaring the token-tree attribute contents into internal AST constucts. This may be too fragile for the long-term.
   * (In particular, it *definitely* breaks when you try to add a contract to a function like this: `fn foo1(x: i32) -> S<{ 23 }> { ... }`, because its token-tree based search for where to inject the internal AST constructs cannot immediately see that the `{ 23 }` is within a generics list. I think we can live for this for the short-term, i.e. land the work, and continue working on it while in parallel adding a new attribute variant that takes a token-tree attribute alongside an AST annotation, which would completely resolve the issue here.)

* the *intent* of `-Z contract-checks` is that it behaves like `-Z ub-checks`, in that we do not prematurely commit to including or excluding the contract evaluation in upstream crates (most notably, `core` and `std`). But the current test suite does not actually *check* that this is the case. Ideally the test suite would be extended with a multi-crate test that explores the matrix of enabling/disabling contracts on both the upstream lib and final ("leaf") bin crates.
@RalfJung
Copy link
Member

@celinval what's the status of the design document that you started here? Now that there is an implementation in rustc, it'd be good to have e.g. a page on the dev guide explaining the overall design, and in particular explaining the lowering of the attributes, as that can be quite hard to follow otherwise.

@celinval
Copy link
Contributor

I just finished updating the design document, and I included the changes to support adding contract to constant functions.I believe there's a request to hold a design review with the compiler team, but I don't know when it will be.

I can create a PR to the dev-guide. Should I wait for the design review meeting?

@RalfJung
Copy link
Member

Maybe it makes sense to wait until after the meeting then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-experimental Blocker: In-tree experiment; RFC pending, not yet approved or unneeded (requires FCP to stabilize). C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-contracts `#![feature(contracts)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
Status: Exploration
Development

No branches or pull requests

7 participants