1 // This is a test adapted from a minimization of the code from
2 // rust-lang/rust#52934, where an accidental disabling of
3 // two-phase-borrows (in the initial 2018 edition integration) broke
4 // Clippy, but the scenarios where it was breaking were subtle enough
5 // that we decided it warranted its own unit test, and pnkfelix
6 // decided to use that test as an opportunity to illustrate the cases.
10 enum Expr { Closure(BodyId), Others }
11 struct Body { value: Expr }
13 struct Map { body: Body, }
14 impl Map { fn body(&self, _: BodyId) -> &Body { unimplemented!() } }
16 struct SpanlessHash<'a> { cx: &'a Map, cx_mut: &'a mut Map }
18 impl <'a> SpanlessHash<'a> {
20 let _mut_borrow = &mut *self;
21 let _access = self.cx;
22 //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503]
26 fn hash_expr(&mut self, e: &Expr) {
28 Expr::Closure(eid) => {
29 // Accepted by AST-borrowck for erroneous reasons
30 // (rust-lang/rust#38899).
32 // Not okay without two-phase borrows: the implicit
33 // `&mut self` of the receiver is evaluated first, and
34 // that conflicts with the `self.cx` access during
35 // argument evaluation, as demonstrated in `fn demo`
38 // Okay if we have two-phase borrows. Note that even
39 // if `self.cx.body(..)` holds onto a reference into
40 // `self.cx`, `self.cx` is an immutable-borrow, so
41 // nothing in the activation for `self.hash_expr(..)`
42 // can interfere with that immutable borrow.
43 self.hash_expr(&self.cx.body(eid).value);
49 fn hash_expr_mut(&mut self, e: &Expr) {
51 Expr::Closure(eid) => {
52 // Not okay: the call to `self.cx_mut.body(eid)` might
53 // hold on to some mutably borrowed state in
54 // `self.cx_mut`, which would then interfere with the
55 // eventual activation of the `self` mutable borrow
56 // for `self.hash_expr(..)`
57 self.hash_expr(&self.cx_mut.body(eid).value);
58 //~^ ERROR cannot borrow `*self`
67 trait LateLintPass<'a> { }
71 fn new(_: &Session) -> Self { TrivialPass }
72 fn new_mut(_: &mut Session) -> Self { TrivialPass }
75 struct CapturePass<'a> { s: &'a Session }
76 impl<'a> CapturePass<'a> {
77 fn new(s: &'a Session) -> Self { CapturePass { s } }
78 fn new_mut(s: &'a mut Session) -> Self { CapturePass { s } }
81 impl<'a> LateLintPass<'a> for TrivialPass { }
82 impl<'a, 'b> LateLintPass<'a> for CapturePass<'b> { }
84 struct Registry<'a> { sess_mut: &'a mut Session }
85 impl<'a> Registry<'a> {
86 fn register_static(&mut self, _: Box<dyn LateLintPass + 'static>) { }
88 // Note: there isn't an interesting distinction between these
89 // different methods explored by any of the cases in the test
90 // below. pnkfelix just happened to write these cases out while
91 // exploring variations on `dyn for <'a> Trait<'a> + 'static`, and
92 // then decided to keep these particular ones in.
93 fn register_bound(&mut self, _: Box<dyn LateLintPass + 'a>) { }
94 fn register_univ(&mut self, _: Box<dyn for <'b> LateLintPass<'b> + 'a>) { }
95 fn register_ref(&mut self, _: &dyn LateLintPass) { }
98 fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) {
99 // Not okay without two-phase borrows: The implicit `&mut reg` of
100 // the receiver is evaluaated first, and that conflicts with the
101 // `reg.sess_mut` access during argument evaluation.
103 // Okay if we have two-phase borrows: inner borrows do not survive
104 // to the actual method invocation, because `TrivialPass::new`
105 // cannot (according to its type) keep them alive.
107 reg.register_static(Box::new(TrivialPass::new(®.sess_mut)));
109 reg.register_bound(Box::new(TrivialPass::new(®.sess_mut)));
111 reg.register_univ(Box::new(TrivialPass::new(®.sess_mut)));
113 reg.register_ref(&TrivialPass::new(®.sess_mut));
115 // These are not okay: the inner mutable borrows immediately
116 // conflict with the outer borrow/reservation, even with support
117 // for two-phase borrows.
119 reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
120 //~^ ERROR cannot borrow `reg.sess_mut`
122 reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
123 //~^ ERROR cannot borrow `reg.sess_mut`
125 reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
126 //~^ ERROR cannot borrow `reg.sess_mut`
128 reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
129 //~^ ERROR cannot borrow `reg.sess_mut`
131 // These are not okay: the inner borrows may reach the actual
132 // method invocation, because `CapturePass::new` might (according
133 // to its type) keep them alive.
135 // (Also, we don't test `register_static` on CapturePass because
136 // that will fail to get past lifetime inference.)
138 reg.register_bound(Box::new(CapturePass::new(®.sess_mut)));
139 //~^ ERROR cannot borrow `*reg` as mutable
141 reg.register_univ(Box::new(CapturePass::new(®.sess_mut)));
142 //~^ ERROR cannot borrow `*reg` as mutable
144 reg.register_ref(&CapturePass::new(®.sess_mut));
145 //~^ ERROR cannot borrow `*reg` as mutable
147 // These are not okay: the inner mutable borrows immediately
148 // conflict with the outer borrow/reservation, even with support
149 // for two-phase borrows.
151 // (Again, we don't test `register_static` on CapturePass because
152 // that will fail to get past lifetime inference.)
154 reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
155 //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
156 //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time
158 reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
159 //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
160 //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time
162 reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut));
163 //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time
164 //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time