8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
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
+
11
40
// ----------------------------------------------------------------------
12
41
// Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety
13
42
// of the scope S, presuming that the returned set of loans `Ls` are honored.
@@ -39,7 +68,7 @@ impl borrowck_ctxt {
39
68
scope_region : scope_region,
40
69
loans : ~[ ]
41
70
} ;
42
- match lc. loan ( cmt, mutbl) {
71
+ match lc. loan ( cmt, mutbl, true ) {
43
72
Err ( ref e) => Err ( ( * e) ) ,
44
73
Ok ( ( ) ) => {
45
74
let LoanContext { loans, _} = move lc;
@@ -62,46 +91,25 @@ struct LoanContext {
62
91
impl LoanContext {
63
92
fn tcx ( & self ) -> ty:: ctxt { self . bccx . tcx }
64
93
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
+ */
86
112
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 < ( ) > {
105
113
debug ! ( "loan(%s, %s)" ,
106
114
self . bccx. cmt_to_repr( cmt) ,
107
115
self . bccx. mut_to_str( req_mutbl) ) ;
@@ -123,13 +131,14 @@ impl LoanContext {
123
131
}
124
132
cat_local( local_id) | cat_arg( local_id) | cat_self( local_id) => {
125
133
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)
127
136
}
128
137
cat_stack_upvar( cmt) => {
129
- self . loan ( cmt, req_mutbl) // NDM correct?
138
+ self . loan ( cmt, req_mutbl, owns_lent_data )
130
139
}
131
140
cat_discr( base, _) => {
132
- self . loan ( base, req_mutbl)
141
+ self . loan ( base, req_mutbl, owns_lent_data )
133
142
}
134
143
cat_comp( cmt_base, comp_field( _, m) ) |
135
144
cat_comp( cmt_base, comp_index( _, m) ) => {
@@ -139,36 +148,41 @@ impl LoanContext {
139
148
// that case, it must also be embedded in an immutable
140
149
// location, or else the whole structure could be
141
150
// 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)
143
153
}
144
154
cat_comp( cmt_base, comp_tuple) |
145
155
cat_comp( cmt_base, comp_anon_field) => {
146
156
// 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)
148
159
}
149
160
cat_comp( cmt_base, comp_variant( enum_did) ) => {
150
161
// For enums, the memory is unstable if there are multiple
151
162
// variants, because if the enum value is overwritten then
152
163
// the memory changes type.
153
164
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)
155
167
} 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)
157
170
}
158
171
}
159
172
cat_deref( cmt_base, _, uniq_ptr) => {
160
173
// For unique pointers, the memory being pointed out is
161
174
// unstable because if the unique pointer is overwritten
162
175
// 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)
164
178
}
165
179
cat_deref( cmt_base, _, region_ptr( ast:: m_mutbl, region) ) => {
166
180
// Mutable data can be loaned out as immutable or const. We must
167
181
// loan out the base as well as the main memory. For example,
168
182
// if someone borrows `*b`, we want to borrow `b` as immutable
169
183
// 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 )
172
186
}
173
187
}
174
188
cat_deref( _, _, unsafe_ptr) |
@@ -189,7 +203,8 @@ impl LoanContext {
189
203
cmt : cmt ,
190
204
cmt_base : cmt ,
191
205
req_mutbl : ast:: mutability ,
192
- comp_mutbl : ast:: mutability ) -> bckres < ( ) > {
206
+ comp_mutbl : ast:: mutability ,
207
+ owns_lent_data : bool ) -> bckres < ( ) > {
193
208
// Determine the mutability that the base component must have,
194
209
// given the required mutability of the pointer (`req_mutbl`)
195
210
// and the declared mutability of the component (`comp_mutbl`).
@@ -243,10 +258,11 @@ impl LoanContext {
243
258
( m_const, _) => m_const // (5)
244
259
} ;
245
260
246
- do self. loan ( cmt_base, base_mutbl) . chain |_ok| {
261
+ do self. loan ( cmt_base, base_mutbl, owns_lent_data ) . chain |_ok| {
247
262
// can use static for the scope because the base
248
263
// 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)
250
266
}
251
267
}
252
268
@@ -256,13 +272,69 @@ impl LoanContext {
256
272
fn loan_unstable_deref ( & self ,
257
273
cmt : cmt ,
258
274
cmt_base : cmt ,
259
- req_mutbl : ast:: mutability ) -> bckres < ( ) > {
275
+ req_mutbl : ast:: mutability ,
276
+ owns_lent_data : bool ) -> bckres < ( ) >
277
+ {
260
278
// Variant components: the base must be immutable, because
261
279
// if it is overwritten, the types of the embedded data
262
280
// could change.
263
- do self . loan ( cmt_base, m_imm) . chain |_| {
281
+ do self . loan ( cmt_base, m_imm, owns_lent_data ) . chain |_| {
264
282
// 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 ) } ) ;
266
338
}
267
339
}
268
340
}
0 commit comments