-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 ?)
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 |
ddf5369
to
2399210
Compare
This comment has been minimized.
This comment has been minimized.
Hmm. I don’t think I want contract_checks to be part of the explicit suggestions emitted by that lint; that would imply a level of stability that I do not want to commit to, I’ll try to investigate that bit further. |
Actually, .... even though I'm still not sure about whether it is ideal to include So I'll just take the shortcut and add |
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...)
…ract checks are run, and 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.
…ower it into the previously added contract 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).
…xtensions added earlier.
…ostcondition predicate.
…e user exposed versus the interface we want to ship externally eventually.
9ef90b2
to
4d43770
Compare
☔ The latest upstream changes (presumably #134269) made this pull request unmergeable. Please resolve the merge conflicts. |
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.