Skip to content

Commit ac8c9d7

Browse files
committed
---
yaml --- r: 42715 b: refs/heads/try c: 4b15bfd h: refs/heads/master i: 42713: d4ee6e5 42711: c53497b v: v3
1 parent af2906f commit ac8c9d7

File tree

2 files changed

+129
-57
lines changed

2 files changed

+129
-57
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
refs/heads/master: 19dfec2aaf746535de1521f68421f9980dbf25de
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 2f46b763da2c098913884f101b6d71d69af41b49
5-
refs/heads/try: b4acde3bf7451cc20d6690ca2d3266f24bf9f477
5+
refs/heads/try: 4b15bfde8133768d8fc517eeb8064bd2f9bcddd5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: a810c03263670238bccd64cabb12a23a46e3a278

branches/try/src/librustc/middle/borrowck/loan.rs

Lines changed: 128 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,35 @@
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 {
6291
impl 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

Comments
 (0)