-
Notifications
You must be signed in to change notification settings - Fork 129
Introduce rmc::proof function attribute #668
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
Conversation
celinval
left a comment
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 so happy to see this going through! I know this is just a draft, but I left a few comments. Cheers
| } | ||
|
|
||
| pub fn filename(&self) -> Option<String> { | ||
| match self { |
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.
Just a suggestion. This could be a one liner:
if let Location::Loc { file, .. } = self { Some(file.to_string) } else { None }
| /// | ||
| /// Currently, this is only proof harness annotations. | ||
| /// i.e. `#[rmc::proof]` (which rmc-annotations translates to `#[rmctool::proof]` for us to handle here) | ||
| fn codegen_rmctool_attributes(&mut self) { |
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 would suggest renaming to something like
collect_rmc_attributes? This is not quite codegen. - I was also wondering if these functions should be inside
metadata.rsinstead. - Why do we need
&mut?
| fn codegen_rmctool_attributes(&mut self) { | ||
| let instance = self.current_fn().instance(); | ||
|
|
||
| for attr in self.tcx.get_attrs(instance.def_id()) { |
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.
Can you please add a debug statement?
| let instance = self.current_fn().instance(); | ||
|
|
||
| for attr in self.tcx.get_attrs(instance.def_id()) { | ||
| if matches_rmctool_attr(attr, "proof") { |
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.
Can we add a sanity check somewhere that validates the rmctool attributes used in the function?
| } | ||
| } | ||
|
|
||
| fn matches_rmctool_attr(attr: &ast::Attribute, name: &str) -> bool { |
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 would return a set of rmctool attributes. We are planning to add multiple attributes, right? I don't think this method will scale well.
| // but outside RMC, this code is likely never called. | ||
| let mut result = TokenStream::new(); | ||
|
|
||
| result.extend("#[allow(dead_code)]".parse::<TokenStream>().unwrap()); |
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 wouldn't add this. We don't want proof methods to inadvertently make it to the final library / binary. We can either extend with a #[cfg(proof)] or just document that users should do that.
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 thought about additionally branching into having a debug/release version of the macro, with the release removing the function entirely. Would that work for you?
My goal here was to ensure #[proof] is enough all by itself and nothing further needs to be added, just like #[test]
But come to think of it, I think this won't work as-is anyway. If the goal is to let users add rmc as a dev-dependency, then this package (defining the #[proof] macro) wouldn't be in the dependency list anyway during a normal non-test compile. :( Might have to have a rethink about that problem...
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.
Gotcha. I'm OK with the idea of users adding #[proof] by itself. I would just prefer for it to be a no-op if they are not using rmc. I.e., I would prefer if we remove the #[allow(dead_code)].
| pub fn proof(_attr: TokenStream, item: TokenStream) -> TokenStream { | ||
| let mut result = TokenStream::new(); | ||
|
|
||
| result.extend("#[rmctool::proof]".parse::<TokenStream>().unwrap()); |
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.
Can you please add the #[no_mangle] for now? You can link to #661 for us to remove it.
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 thought the need for no_mangle was just the UI problem of predicting the mangled name. This feature is intended to solve that, since we get a map:
{
"pretty_name": "testing",
"mangled_name": "_RNvCs1NZMV7qnTwy_1f7testing",
"original_file": "/home/ubuntu/experiments/proof_anno/f.rs"
}
Is there some other reason for no_mangle? Otherwise, I don't know why I'd add it 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.
I was thinking about addressing that in a follow up PR so this PR doesn't get too big and we can merge it sooner rather than later. If you do add that to this PR, then it's OK to keep it without the no_mangle.
There are two reasons why we rely on the #[no_mangle] today. One is the friendly name and the second is that no_mangle makes the function public.
Remaining things before mergable:
|
|
Regarding # 3, I believe it should still work if you export Maybe we should add an option to rmc to allow switching them or just detect whether user target function is |
|
I think this is ready to merge.
Checklist for me after merge:
My next steps after this are to get started on a "real" Rust |
For the second bullet, we already have: #600 |
celinval
left a comment
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.
Just a few minor comments. Thanks
| } | ||
|
|
||
| /// Update `self` (the goto context) to add the current function as a listed proof harness | ||
| fn handle_rmctool_proof(&mut self) { |
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.
What is the plan for proof options like unwind? Are you thinking about adding arguments to this attribute or creating new 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.
I'm thinking add arguments to this attribute, yes.
| None | ||
| }; | ||
|
|
||
| let metadata = RmcMetadata { proof_harnesses: c.proof_harnesses }; |
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.
Why do we need this?
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 what you mean by 'this'. The RmcMetadata type?) I'm planning on the rmc-metadata file becoming where we emit everything that isn't the symtab. So type_map, function restrictions, and more things like notable/important warnings (instead of just logging them).
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, I mean the copy statement.
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.
Still not sure what the "copy statement" is.
|
I also forgot... can you please a testcase? |
I really want to but nothing reads this yet, so I was going to create an issue to not forget, and include that as part of |
For now, it would at least ensure that things compile and that this code doesn't crash. |
Ah, this code is running by default, so all existing tests are exercising it. We're just not examining the output to see if it's correct (i.e. that proof harnesses show up and only the correct ones, etc) |
Oh wait, you mean add a test that has a harness to that actual branch gets run, even if nothing looks at it. I can do that. |
|
Ok, I've added a |
* Introduce rmc::proof function attribute * add no_mangle as temporary measure to force function codegen
* Introduce rmc::proof function attribute * add no_mangle as temporary measure to force function codegen
Description of changes:
rmc-annotationscrate. This is necessary because to introduce proc macros, they need to be in a crate by themselves. Added as dependency ofrmccrate. (And has to be injected in RMC's rustc flags.)#[rmc::proof]attribute. In the long run, this is meant to "work" (do the reasonable thing) whether under RMC or not. Under RMC (the only thing we use right now), it just expands to#[rmctool::proof]..rmc-metadata.jsonthat will likely just grow to subsume everything we emit that isn't the symbol table (e.g..type_map.json) later on.Resolved issues:
Resolves... figure that out
Call-outs:
#[rmc::proof]must bepubor we silently don't notice it at all. I need to figure out a fix for this. Ideally it'd just work without issue, but I'd even settle for an error check for a missingpubif that's all we can figure out how to do, but even that's not obvious to me since we never callcodegen_functionas that's the problem in the first place!cargo rmc. Notably, though, cargo typically produces a single.rmc-metadata.json(and friends) per-crate. So we'd really just be looking for the proof harnesses in our crate, not from our dependencies. (Or perhaps some similar heuristic. Only from local crates?)Testing:
How is this change tested? TODO - draft PR
Is this a refactor change?
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.