Skip to content

Instantly share code, notes, and snippets.

@Manishearth
Last active March 5, 2023 09:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Manishearth/045ee457d6f81183ec6b to your computer and use it in GitHub Desktop.
Save Manishearth/045ee457d6f81183ec6b to your computer and use it in GitHub Desktop.
struct MyVisitor {
in_allowed: bool,
in_dropper: bool,
map: HashMap<NodeId, NodeId>,
current_block: NodeId,
}
impl Visitor for MyVisitor {
visit_stmt() {
// If it's a StmtDecl
// Check the type of the thing it's assigning to (expr_ty)
// If that type is a Chan, add it's nodeid and the current block
// nodeid to the map
// You can call visit::walk_stmt(self, stmt) after this, but you don't need to and it might require
// special casing since the ident will be visited inside of it and you have to ignore that one.
}
visit_ident(...) {
if !self.in_allowed {
// Do a defmap lookup
// If it's a DefLocal, check if the corresponding NodeId is in the map
// if so, error. The variable is being used when it shouldn't be!
}
if self.in_dropper {
// remove the corresponding def from the hashmap
}
}
// I'm assuming that all allowed methods consuming chan
// don't use self (so are called by `do_something(chan)` and
// not `chan.do_something()`. If not, we can add another case here
// for exprmethodcall. All allowed methods should be marked as `#[allow_chan]`
// or whatever
visit_expr(self, expr) {
if self.in_allowed {
visit::walk_expr(self, expr);
return
}
match expr {
ExprCall(ex, ....) => {
// do a defmap lookup on ex.id
// use middle::ty::has_attr() to see if it
// has the "allow_chan" attribute
// Also check for the `chan_dropper`
// attribute for functions that are allowed to drop it
if has_drop_attribute {
self.in_dropper = true;
self.in_allowed = true;
visit::walk_expr(self, expr);
self.in_dropper = false;
self.in_allowed = false;
return
}
if has_allow_attribute {
self.in_allowed = true;
visit::walk_expr(self, expr);
self.in_allowed = false;
return
}
}
}
visit::walk_expr(self, expr);
}
visit_block(self, block) {
let id = block.id
self.current_block = id; // will change whilst recursing
visit::walk_block(self, block)
// Check if there still is an entry linked to `id`
// in self.map. If so, error, the variable was implicitly dropped
}
}
// Example of an allowed function
#[allow_chan]
fn send<T>(c: Chan<T>, Data<T>) -> Chan<T> {
// do stuff
c
}
// Example of function allowed to drop it
#[chan_dropper]
fn drop_chan<T>(c: Chan<T>) { // DO NOT return the chan!
// do stuff
}
// Now, to bundle all this up, create a LintPass, and within `check_fn`, have your visitor walk down the function
@Sanjeevi567
Copy link

Drop protected paper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment