| // This is a test adapted from a minimization of the code from |
| // rust-lang/rust#52934, where an accidental disabling of |
| // two-phase-borrows (in the initial 2018 edition integration) broke |
| // Clippy, but the scenarios where it was breaking were subtle enough |
| // that we decided it warranted its own unit test, and pnkfelix |
| // decided to use that test as an opportunity to illustrate the cases. |
| |
| #[derive(Copy, Clone)] |
| struct BodyId; |
| enum Expr { Closure(BodyId), Others } |
| struct Body { value: Expr } |
| |
| struct Map { body: Body, } |
| impl Map { fn body(&self, _: BodyId) -> &Body { unimplemented!() } } |
| |
| struct SpanlessHash<'a> { cx: &'a Map, cx_mut: &'a mut Map } |
| |
| impl <'a> SpanlessHash<'a> { |
| fn demo(&mut self) { |
| let _mut_borrow = &mut *self; |
| let _access = self.cx; |
| //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] |
| _mut_borrow; |
| } |
| |
| fn hash_expr(&mut self, e: &Expr) { |
| match *e { |
| Expr::Closure(eid) => { |
| // Accepted by AST-borrowck for erroneous reasons |
| // (rust-lang/rust#38899). |
| // |
| // Not okay without two-phase borrows: the implicit |
| // `&mut self` of the receiver is evaluated first, and |
| // that conflicts with the `self.cx` access during |
| // argument evaluation, as demonstrated in `fn demo` |
| // above. |
| // |
| // Okay if we have two-phase borrows. Note that even |
| // if `self.cx.body(..)` holds onto a reference into |
| // `self.cx`, `self.cx` is an immutable-borrow, so |
| // nothing in the activation for `self.hash_expr(..)` |
| // can interfere with that immutable borrow. |
| self.hash_expr(&self.cx.body(eid).value); |
| }, |
| _ => {} |
| } |
| } |
| |
| fn hash_expr_mut(&mut self, e: &Expr) { |
| match *e { |
| Expr::Closure(eid) => { |
| // Not okay: the call to `self.cx_mut.body(eid)` might |
| // hold on to some mutably borrowed state in |
| // `self.cx_mut`, which would then interfere with the |
| // eventual activation of the `self` mutable borrow |
| // for `self.hash_expr(..)` |
| self.hash_expr(&self.cx_mut.body(eid).value); |
| //~^ ERROR cannot borrow `*self` |
| }, |
| _ => {} |
| } |
| } |
| } |
| |
| struct Session; |
| struct Config; |
| trait LateLintPass<'a> { } |
| |
| struct TrivialPass; |
| impl TrivialPass { |
| fn new(_: &Session) -> Self { TrivialPass } |
| fn new_mut(_: &mut Session) -> Self { TrivialPass } |
| } |
| |
| struct CapturePass<'a> { s: &'a Session } |
| impl<'a> CapturePass<'a> { |
| fn new(s: &'a Session) -> Self { CapturePass { s } } |
| fn new_mut(s: &'a mut Session) -> Self { CapturePass { s } } |
| } |
| |
| impl<'a> LateLintPass<'a> for TrivialPass { } |
| impl<'a, 'b> LateLintPass<'a> for CapturePass<'b> { } |
| |
| struct Registry<'a> { sess_mut: &'a mut Session } |
| impl<'a> Registry<'a> { |
| fn register_static(&mut self, _: Box<dyn LateLintPass + 'static>) { } |
| |
| // Note: there isn't an interesting distinction between these |
| // different methods explored by any of the cases in the test |
| // below. pnkfelix just happened to write these cases out while |
| // exploring variations on `dyn for <'a> Trait<'a> + 'static`, and |
| // then decided to keep these particular ones in. |
| fn register_bound(&mut self, _: Box<dyn LateLintPass + 'a>) { } |
| fn register_univ(&mut self, _: Box<dyn for <'b> LateLintPass<'b> + 'a>) { } |
| fn register_ref(&mut self, _: &dyn LateLintPass) { } |
| } |
| |
| fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { |
| // Not okay without two-phase borrows: The implicit `&mut reg` of |
| // the receiver is evaluaated first, and that conflicts with the |
| // `reg.sess_mut` access during argument evaluation. |
| // |
| // Okay if we have two-phase borrows: inner borrows do not survive |
| // to the actual method invocation, because `TrivialPass::new` |
| // cannot (according to its type) keep them alive. |
| let reg = mk_reg(); |
| reg.register_static(Box::new(TrivialPass::new(®.sess_mut))); |
| let reg = mk_reg(); |
| reg.register_bound(Box::new(TrivialPass::new(®.sess_mut))); |
| let reg = mk_reg(); |
| reg.register_univ(Box::new(TrivialPass::new(®.sess_mut))); |
| let reg = mk_reg(); |
| reg.register_ref(&TrivialPass::new(®.sess_mut)); |
| |
| // These are not okay: the inner mutable borrows immediately |
| // conflict with the outer borrow/reservation, even with support |
| // for two-phase borrows. |
| let reg = mk_reg(); |
| reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); |
| //~^ ERROR cannot borrow `reg.sess_mut` |
| let reg = mk_reg(); |
| reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); |
| //~^ ERROR cannot borrow `reg.sess_mut` |
| let reg = mk_reg(); |
| reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); |
| //~^ ERROR cannot borrow `reg.sess_mut` |
| let reg = mk_reg(); |
| reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); |
| //~^ ERROR cannot borrow `reg.sess_mut` |
| |
| // These are not okay: the inner borrows may reach the actual |
| // method invocation, because `CapturePass::new` might (according |
| // to its type) keep them alive. |
| // |
| // (Also, we don't test `register_static` on CapturePass because |
| // that will fail to get past lifetime inference.) |
| let reg = mk_reg(); |
| reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); |
| //~^ ERROR cannot borrow `*reg` as mutable |
| let reg = mk_reg(); |
| reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); |
| //~^ ERROR cannot borrow `*reg` as mutable |
| let reg = mk_reg(); |
| reg.register_ref(&CapturePass::new(®.sess_mut)); |
| //~^ ERROR cannot borrow `*reg` as mutable |
| |
| // These are not okay: the inner mutable borrows immediately |
| // conflict with the outer borrow/reservation, even with support |
| // for two-phase borrows. |
| // |
| // (Again, we don't test `register_static` on CapturePass because |
| // that will fail to get past lifetime inference.) |
| let reg = mk_reg(); |
| reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); |
| //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time |
| //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time |
| let reg = mk_reg(); |
| reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); |
| //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time |
| //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time |
| let reg = mk_reg(); |
| reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); |
| //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time |
| //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time |
| } |
| |
| fn main() { } |