1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
// 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() { }
|