]> git.lizzy.rs Git - rust.git/blob - tests/ui/borrowck/two-phase-surprise-no-conflict.rs
Rollup merge of #106726 - cmorin6:fix-comment-typos, r=Nilstrieb
[rust.git] / tests / ui / borrowck / two-phase-surprise-no-conflict.rs
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.
7
8 #[derive(Copy, Clone)]
9 struct BodyId;
10 enum Expr { Closure(BodyId), Others }
11 struct Body { value: Expr }
12
13 struct Map { body: Body, }
14 impl Map { fn body(&self, _: BodyId) -> &Body { unimplemented!() } }
15
16 struct SpanlessHash<'a> { cx: &'a Map, cx_mut: &'a mut Map }
17
18 impl <'a> SpanlessHash<'a> {
19     fn demo(&mut self) {
20         let _mut_borrow = &mut *self;
21         let _access = self.cx;
22         //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503]
23         _mut_borrow;
24     }
25
26     fn hash_expr(&mut self, e: &Expr) {
27         match *e {
28             Expr::Closure(eid) => {
29                 // Accepted by AST-borrowck for erroneous reasons
30                 // (rust-lang/rust#38899).
31                 //
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`
36                 // above.
37                 //
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);
44             },
45             _ => {}
46         }
47     }
48
49     fn hash_expr_mut(&mut self, e: &Expr) {
50         match *e {
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`
59             },
60             _ => {}
61         }
62     }
63 }
64
65 struct Session;
66 struct Config;
67 trait LateLintPass<'a> { }
68
69 struct TrivialPass;
70 impl TrivialPass {
71     fn new(_: &Session) -> Self { TrivialPass }
72     fn new_mut(_: &mut Session) -> Self { TrivialPass }
73 }
74
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 } }
79 }
80
81 impl<'a> LateLintPass<'a> for TrivialPass { }
82 impl<'a, 'b> LateLintPass<'a> for CapturePass<'b> { }
83
84 struct Registry<'a> { sess_mut: &'a mut Session }
85 impl<'a> Registry<'a> {
86     fn register_static(&mut self, _: Box<dyn LateLintPass + 'static>) { }
87
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) { }
96 }
97
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.
102     //
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.
106     let reg = mk_reg();
107     reg.register_static(Box::new(TrivialPass::new(&reg.sess_mut)));
108     let reg = mk_reg();
109     reg.register_bound(Box::new(TrivialPass::new(&reg.sess_mut)));
110     let reg = mk_reg();
111     reg.register_univ(Box::new(TrivialPass::new(&reg.sess_mut)));
112     let reg = mk_reg();
113     reg.register_ref(&TrivialPass::new(&reg.sess_mut));
114
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.
118     let reg = mk_reg();
119     reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut)));
120     //~^ ERROR cannot borrow `reg.sess_mut`
121     let reg = mk_reg();
122     reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
123     //~^ ERROR cannot borrow `reg.sess_mut`
124     let reg = mk_reg();
125     reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut)));
126     //~^ ERROR cannot borrow `reg.sess_mut`
127     let reg = mk_reg();
128     reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut));
129     //~^ ERROR cannot borrow `reg.sess_mut`
130
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.
134     //
135     // (Also, we don't test `register_static` on CapturePass because
136     // that will fail to get past lifetime inference.)
137     let reg = mk_reg();
138     reg.register_bound(Box::new(CapturePass::new(&reg.sess_mut)));
139     //~^ ERROR cannot borrow `*reg` as mutable
140     let reg = mk_reg();
141     reg.register_univ(Box::new(CapturePass::new(&reg.sess_mut)));
142     //~^ ERROR cannot borrow `*reg` as mutable
143     let reg = mk_reg();
144     reg.register_ref(&CapturePass::new(&reg.sess_mut));
145     //~^ ERROR cannot borrow `*reg` as mutable
146
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.
150     //
151     // (Again, we don't test `register_static` on CapturePass because
152     // that will fail to get past lifetime inference.)
153     let reg = mk_reg();
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
157     let reg = mk_reg();
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
161     let reg = mk_reg();
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
165 }
166
167 fn main() { }