88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ /*!
12+
13+ The `Loan` module deals with borrows of *uniquely mutable* data. We
14+ say that data is uniquely mutable if the current activation (stack
15+ frame) controls the only mutable reference to the data. The most
16+ common way that this can occur is if the current activation owns the
17+ data being borrowed, but it can also occur with `&mut` pointers. The
18+ primary characteristic of uniquely mutable data is that, at any given
19+ time, there is at most one path that can be used to mutate it, and
20+ that path is only accessible from the top stack frame.
21+
22+ Given that some data found at a path P is being borrowed to a borrowed
23+ pointer with mutability M and lifetime L, the job of the code in this
24+ module is to compute the set of *loans* that are necessary to ensure
25+ that (1) the data found at P outlives L and that (2) if M is mutable
26+ then the path P will not be modified directly or indirectly except
27+ through that pointer. A *loan* is the combination of a path P_L, a
28+ mutability M_L, and a lifetime L_L where:
29+
30+ - The path P_L indicates what data has been lent.
31+ - The mutability M_L indicates the access rights on the data:
32+ - const: the data cannot be moved
33+ - immutable/mutable: the data cannot be moved or mutated
34+ - The lifetime L_L indicates the *scope* of the loan.
35+
36+ XXX --- much more needed, don't have time to write this all up now
37+
38+ */
39+
1140// ----------------------------------------------------------------------
1241// Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety
1342// of the scope S, presuming that the returned set of loans `Ls` are honored.
@@ -39,7 +68,7 @@ impl borrowck_ctxt {
3968 scope_region : scope_region,
4069 loans : ~[ ]
4170 } ;
42- match lc. loan ( cmt, mutbl) {
71+ match lc. loan ( cmt, mutbl, true ) {
4372 Err ( ref e) => Err ( ( * e) ) ,
4473 Ok ( ( ) ) => {
4574 let LoanContext { loans, _} = move lc;
@@ -62,46 +91,25 @@ struct LoanContext {
6291impl LoanContext {
6392 fn tcx ( & self ) -> ty:: ctxt { self . bccx . tcx }
6493
65- fn issue_loan ( & self ,
66- cmt : cmt ,
67- scope_ub : ty:: Region ,
68- req_mutbl : ast:: mutability ) -> bckres < ( ) > {
69- if self . bccx . is_subregion_of ( self . scope_region , scope_ub) {
70- match req_mutbl {
71- m_mutbl => {
72- // We do not allow non-mutable data to be loaned
73- // out as mutable under any circumstances.
74- if cmt. mutbl != m_mutbl {
75- return Err ( { cmt: cmt,
76- code: err_mutbl ( req_mutbl) } ) ;
77- }
78- }
79- m_const | m_imm => {
80- // However, mutable data can be loaned out as
81- // immutable (and any data as const). The
82- // `check_loans` pass will then guarantee that no
83- // writes occur for the duration of the loan.
84- }
85- }
94+ fn loan ( & self ,
95+ cmt : cmt ,
96+ req_mutbl : ast:: mutability ,
97+ owns_lent_data : bool ) -> bckres < ( ) >
98+ {
99+ /*!
100+ *
101+ * The main routine.
102+ *
103+ * # Parameters
104+ *
105+ * - `cmt`: the categorization of the data being borrowed
106+ * - `req_mutbl`: the mutability of the borrowed pointer
107+ * that was created
108+ * - `owns_lent_data`: indicates whether `cmt` owns the
109+ * data that is being lent. See
110+ * discussion in `issue_loan()`.
111+ */
86112
87- self . loans . push ( Loan {
88- // Note: cmt.lp must be Some(_) because otherwise this
89- // loan process does not apply at all.
90- lp : cmt. lp . get ( ) ,
91- cmt : cmt,
92- mutbl : req_mutbl
93- } ) ;
94- return Ok ( ( ) ) ;
95- } else {
96- // The loan being requested lives longer than the data
97- // being loaned out!
98- return Err ( { cmt: cmt,
99- code: err_out_of_scope ( scope_ub,
100- self . scope_region ) } ) ;
101- }
102- }
103-
104- fn loan ( & self , cmt : cmt , req_mutbl : ast:: mutability ) -> bckres < ( ) > {
105113 debug ! ( "loan(%s, %s)" ,
106114 self . bccx. cmt_to_repr( cmt) ,
107115 self . bccx. mut_to_str( req_mutbl) ) ;
@@ -123,13 +131,14 @@ impl LoanContext {
123131 }
124132 cat_local( local_id) | cat_arg( local_id) | cat_self( local_id) => {
125133 let local_scope_id = self . tcx ( ) . region_map . get ( local_id) ;
126- self . issue_loan ( cmt, ty:: re_scope ( local_scope_id) , req_mutbl)
134+ self . issue_loan ( cmt, ty:: re_scope ( local_scope_id) , req_mutbl,
135+ owns_lent_data)
127136 }
128137 cat_stack_upvar( cmt) => {
129- self . loan ( cmt, req_mutbl) // NDM correct?
138+ self . loan ( cmt, req_mutbl, owns_lent_data )
130139 }
131140 cat_discr( base, _) => {
132- self . loan ( base, req_mutbl)
141+ self . loan ( base, req_mutbl, owns_lent_data )
133142 }
134143 cat_comp( cmt_base, comp_field( _, m) ) |
135144 cat_comp( cmt_base, comp_index( _, m) ) => {
@@ -139,36 +148,41 @@ impl LoanContext {
139148 // that case, it must also be embedded in an immutable
140149 // location, or else the whole structure could be
141150 // overwritten and the component along with it.
142- self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m)
151+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m,
152+ owns_lent_data)
143153 }
144154 cat_comp( cmt_base, comp_tuple) |
145155 cat_comp( cmt_base, comp_anon_field) => {
146156 // As above.
147- self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm)
157+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm,
158+ owns_lent_data)
148159 }
149160 cat_comp( cmt_base, comp_variant( enum_did) ) => {
150161 // For enums, the memory is unstable if there are multiple
151162 // variants, because if the enum value is overwritten then
152163 // the memory changes type.
153164 if ty:: enum_is_univariant ( self . bccx . tcx , enum_did) {
154- self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm)
165+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm,
166+ owns_lent_data)
155167 } else {
156- self . loan_unstable_deref ( cmt, cmt_base, req_mutbl)
168+ self . loan_unstable_deref ( cmt, cmt_base, req_mutbl,
169+ owns_lent_data)
157170 }
158171 }
159172 cat_deref( cmt_base, _, uniq_ptr) => {
160173 // For unique pointers, the memory being pointed out is
161174 // unstable because if the unique pointer is overwritten
162175 // then the memory is freed.
163- self . loan_unstable_deref ( cmt, cmt_base, req_mutbl)
176+ self . loan_unstable_deref ( cmt, cmt_base, req_mutbl,
177+ owns_lent_data)
164178 }
165179 cat_deref( cmt_base, _, region_ptr( ast:: m_mutbl, region) ) => {
166180 // Mutable data can be loaned out as immutable or const. We must
167181 // loan out the base as well as the main memory. For example,
168182 // if someone borrows `*b`, we want to borrow `b` as immutable
169183 // as well.
170- do self . loan ( cmt_base, m_imm) . chain |_| {
171- self . issue_loan ( cmt, region, m_const)
184+ do self . loan ( cmt_base, m_imm, false ) . chain |_| {
185+ self . issue_loan ( cmt, region, m_const, owns_lent_data )
172186 }
173187 }
174188 cat_deref( _, _, unsafe_ptr) |
@@ -189,7 +203,8 @@ impl LoanContext {
189203 cmt : cmt ,
190204 cmt_base : cmt ,
191205 req_mutbl : ast:: mutability ,
192- comp_mutbl : ast:: mutability ) -> bckres < ( ) > {
206+ comp_mutbl : ast:: mutability ,
207+ owns_lent_data : bool ) -> bckres < ( ) > {
193208 // Determine the mutability that the base component must have,
194209 // given the required mutability of the pointer (`req_mutbl`)
195210 // and the declared mutability of the component (`comp_mutbl`).
@@ -243,10 +258,11 @@ impl LoanContext {
243258 ( m_const, _) => m_const // (5)
244259 } ;
245260
246- do self. loan ( cmt_base, base_mutbl) . chain |_ok| {
261+ do self. loan ( cmt_base, base_mutbl, owns_lent_data ) . chain |_ok| {
247262 // can use static for the scope because the base
248263 // determines the lifetime, ultimately
249- self . issue_loan ( cmt, ty:: re_static, req_mutbl)
264+ self . issue_loan ( cmt, ty:: re_static, req_mutbl,
265+ owns_lent_data)
250266 }
251267 }
252268
@@ -256,13 +272,69 @@ impl LoanContext {
256272 fn loan_unstable_deref ( & self ,
257273 cmt : cmt ,
258274 cmt_base : cmt ,
259- req_mutbl : ast:: mutability ) -> bckres < ( ) > {
275+ req_mutbl : ast:: mutability ,
276+ owns_lent_data : bool ) -> bckres < ( ) >
277+ {
260278 // Variant components: the base must be immutable, because
261279 // if it is overwritten, the types of the embedded data
262280 // could change.
263- do self . loan ( cmt_base, m_imm) . chain |_| {
281+ do self . loan ( cmt_base, m_imm, owns_lent_data ) . chain |_| {
264282 // can use static, as in loan_stable_comp()
265- self . issue_loan ( cmt, ty:: re_static, req_mutbl)
283+ self . issue_loan ( cmt, ty:: re_static, req_mutbl,
284+ owns_lent_data)
285+ }
286+ }
287+
288+ fn issue_loan ( & self ,
289+ cmt : cmt ,
290+ scope_ub : ty:: Region ,
291+ req_mutbl : ast:: mutability ,
292+ owns_lent_data : bool ) -> bckres < ( ) >
293+ {
294+ // Subtle: the `scope_ub` is the maximal lifetime of `cmt`.
295+ // Therefore, if `cmt` owns the data being lent, then the
296+ // scope of the loan must be less than `scope_ub`, or else the
297+ // data would be freed while the loan is active.
298+ //
299+ // However, if `cmt` does *not* own the data being lent, then
300+ // it is ok if `cmt` goes out of scope during the loan. This
301+ // can occur when you have an `&mut` parameter that is being
302+ // reborrowed.
303+
304+ if !owns_lent_data ||
305+ self . bccx . is_subregion_of ( self . scope_region , scope_ub)
306+ {
307+ match req_mutbl {
308+ m_mutbl => {
309+ // We do not allow non-mutable data to be loaned
310+ // out as mutable under any circumstances.
311+ if cmt. mutbl != m_mutbl {
312+ return Err ( { cmt: cmt,
313+ code: err_mutbl ( req_mutbl) } ) ;
314+ }
315+ }
316+ m_const | m_imm => {
317+ // However, mutable data can be loaned out as
318+ // immutable (and any data as const). The
319+ // `check_loans` pass will then guarantee that no
320+ // writes occur for the duration of the loan.
321+ }
322+ }
323+
324+ self . loans . push ( Loan {
325+ // Note: cmt.lp must be Some(_) because otherwise this
326+ // loan process does not apply at all.
327+ lp : cmt. lp . get ( ) ,
328+ cmt : cmt,
329+ mutbl : req_mutbl
330+ } ) ;
331+ return Ok ( ( ) ) ;
332+ } else {
333+ // The loan being requested lives longer than the data
334+ // being loaned out!
335+ return Err ( { cmt: cmt,
336+ code: err_out_of_scope ( scope_ub,
337+ self . scope_region ) } ) ;
266338 }
267339 }
268340}
0 commit comments