-
Notifications
You must be signed in to change notification settings - Fork 13k
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
#[contracts::requires(...)] + #[contracts::ensures(...)] #128045
base: master
Are you sure you want to change the base?
Conversation
r? @fee1-dead rustbot has assigned @fee1-dead. Use |
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
Please add a ui test with an attribute proc-macro aux build that conflicts with |
register( | ||
sym::contracts_requires, | ||
SyntaxExtensionKind::Attr(Box::new(contracts::ExpandRequires)), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This macro should be able to use register_attr!
above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we actually can, if we want to support arbitrary syntax within the contracts::require(...)
-- doesn't register_attr!
mandate that the requires expression conform to ast::MetaItem
, which imposes restrictions on what the syntax can be, i.e. x > 0
wouldn't work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a closer look at this, and this is very unfortunate. I don't believe the current builtin macro setup allows for "path segments"-like namespacing (like rustc_contracts::require
). I've tried to change the builtin macro support to allow multiple "segments" via SmallVec<[Symbol; 2]>
, but as one would expect, that change kept propagating outwards to attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry for my delay in responding here.
@jieyouxu is exactly right.
specifically, register_attr!
expands to a SyntaxExtensionKind::LegacyAttr
, which is where the conformance to ast::MetaItem
is enforced IIRC.
The plan here to support code snippets like x > 0
in a contract form means that we cannot conform to ast::MetaItem
.
(In theory I could try to extend the register_attr!
macro to support expansion to non LegacyAttr
. Is that what you are asking for, @petrochenkov ?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petrochenkov let me know if you want me to make any changes here. Per @pnkfelix comment, using register_attr!
would restrict the input of the contract attributes which is not desirable here. Thanks!
r? compiler |
r? compiler |
I don't know that part of the compiler r? @petrochenkov would you like to review this? |
No. |
r? compiler |
I'll ask T-compiler for another suitable reviewer to take a look at the HIR/MIR parts of the PR, or take over the review. In the mean time, I'll also roll a T-libs reviewer for the libs part. r? jieyouxu |
However, the analogous output for the parser, where it is actively suggesting Hmm. I'll think about bit about what to do about that. Hopefully can suppress suggestion of those tokens in a relatively easy manner. (To be clear, I'm talking about diagnostic output like this: LL | trait Foo { fn a() } //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `}`
| - ^ expected one of `->`, `;`, `rustc_contract_ensures`, `rustc_contract_requires`, `where`, or `{`
| |
| while parsing this `fn` |
This comment has been minimized.
This comment has been minimized.
6fcdfcf
to
e84bae3
Compare
This comment has been minimized.
This comment has been minimized.
e84bae3
to
3b78b85
Compare
This comment has been minimized.
This comment has been minimized.
3b78b85
to
d9b59f3
Compare
This comment has been minimized.
This comment has been minimized.
d9b59f3
to
283d602
Compare
This comment has been minimized.
This comment has been minimized.
From the description:
I had a realization over the weekend: while I myself find the placement of the internal I don't intend to implement that revision myself in the short term (I'd rather see this PR land as-is than block on that, since this fix can land later), but I wanted to mention it as a potential strategy in case anyone was getting worried about that comment above. |
let e = e.as_ref().map(|x| self.lower_expr(x)); | ||
let mut e = e.as_ref().map(|x| self.lower_expr(x)); | ||
if let Some(Some((span, fresh_ident))) = self | ||
.contract | ||
.as_ref() | ||
.map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident))) | ||
{ | ||
let checker_fn = self.expr_ident(span, fresh_ident.0, fresh_ident.2); | ||
let args = if let Some(e) = e { | ||
std::slice::from_ref(e) | ||
} else { | ||
std::slice::from_ref(self.expr_unit(span)) | ||
}; | ||
e = Some(self.expr_call(span, checker_fn, args)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return
s kind of duplicate logic with the trailing expression, something can be improved here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes I agree. It should also be unified with how the Try operator is implemented. I.e. all three cases (return
, ?
, and the tail expression) should all call some common method so that code like this can be controlled in one place.
this.stmt_expr(_contract.span, u) | ||
}; | ||
|
||
let (postcond_checker, _opt_ident, result) = if let Some(ens) = _contract.ensures { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably necessary for later in the PR, but, why is there a tuple field here that we just ignore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I don't think I ever actually used it in the later commits. It was more that I had the info available from when I created the identifier and I wasn't sure if I might need it, so I threaded it through to at least this point...)
9ef90b2
to
4d43770
Compare
☔ The latest upstream changes (presumably #134269) made this pull request unmergeable. Please resolve the merge conflicts. |
|
||
// Found the `fn` keyword, now find the formal parameters. | ||
// | ||
// FIXME: can this fail if you have parentheticals in a generics list, like `fn foo<F: Fn(X) -> Y>` ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: @jdonszelmann pointed out that we could use the parser in rustc_parse
to simplify this code. I'll give it a shot next week.
4d43770
to
eb802c9
Compare
These are hooks to: 1. control whether contract checks are run 2. allow 3rd party tools to intercept and reintepret the results of running contracts.
… to invoke. see test for an example of the kind of injected code that is anticipated here.
…ract lang items includes post-developed commit: do not suggest internal-only keywords as corrections to parse failures. includes post-developed commit: removed tabs that creeped in into rustfmt tool source code. includes post-developed commit, placating rustfmt self dogfooding. includes post-developed commit: add backquotes to prevent markdown checking from trying to treat an attr as a markdown hyperlink/ includes post-developed commit: fix lowering to keep contracts from being erroneously inherited by nested bodies (like closures). Rebase Conflicts: - compiler/rustc_parse/src/parser/diagnostics.rs - compiler/rustc_parse/src/parser/item.rs - compiler/rustc_span/src/hygiene.rs # This is the commit message #2: Remove contracts keywords from diagnostic messages
…xtensions added earlier.
…ostcondition predicate.
The extended syntax for function signature that includes contract clauses should never be user exposed versus the interface we want to ship externally eventually.
eb802c9
to
7baaa4f
Compare
I rebased this PR. I had to change the parser a bit due to #134470. That said, I changed |
cc #128044
Updated contract support: attribute syntax for preconditions and postconditions, implemented via a series of desugarings that culminates in:
-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,Known issues:
My original intent, as described in the MCP (Contracts: Experimental attributes and language intrinsics 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.
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
andstd
). 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.