2018-09-04 09:22:22 -05:00
|
|
|
// 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;
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503]
|
2018-09-04 09:22:22 -05:00
|
|
|
_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
|
2019-09-19 00:17:36 -05:00
|
|
|
// that conflicts with the `self.cx` access during
|
2018-09-04 09:22:22 -05:00
|
|
|
// 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);
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `*self`
|
2018-09-04 09:22:22 -05:00
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `reg.sess_mut`
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `reg.sess_mut`
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `reg.sess_mut`
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `reg.sess_mut`
|
2018-09-04 09:22:22 -05:00
|
|
|
|
|
|
|
// 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)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `*reg` as mutable
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_univ(Box::new(CapturePass::new(®.sess_mut)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `*reg` as mutable
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_ref(&CapturePass::new(®.sess_mut));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ ERROR cannot borrow `*reg` as mutable
|
2018-09-04 09:22:22 -05:00
|
|
|
|
|
|
|
// 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)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ 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
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ 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
|
2018-09-04 09:22:22 -05:00
|
|
|
let reg = mk_reg();
|
|
|
|
reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
|
2019-04-22 02:40:08 -05:00
|
|
|
//~^ 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
|
2018-09-04 09:22:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() { }
|