Skip to content

Commit f60a7c4

Browse files
committed
Fix regionck to consider bounds on a proc when capturing variables
1 parent b516532 commit f60a7c4

File tree

5 files changed

+96
-4
lines changed

5 files changed

+96
-4
lines changed

src/librustc/middle/typeck/check/regionck.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
15341534

15351535
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
15361536
cmt: mc::cmt) {
1537+
/*!
1538+
* Indicates that `cmt` is being directly mutated (e.g., assigned
1539+
* to). If cmt contains any by-ref upvars, this implies that
1540+
* those upvars must be borrowed using an `&mut` borow.
1541+
*/
1542+
15371543
let mut cmt = cmt;
15381544
loop {
15391545
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",

src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,19 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
583583
sub,
584584
"");
585585
}
586+
infer::ProcCapture(span, id) => {
587+
self.tcx.sess.span_err(
588+
span,
589+
format!("captured variable `{}` must be 'static \
590+
to be captured in a proc",
591+
ty::local_var_name_str(self.tcx, id).get())
592+
.as_slice());
593+
note_and_explain_region(
594+
self.tcx,
595+
"captured variable is only valid for ",
596+
sup,
597+
"");
598+
}
586599
infer::IndexSlice(span) => {
587600
self.tcx.sess.span_err(span,
588601
"index of slice outside its lifetime");
@@ -1423,11 +1436,11 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
14231436
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
14241437
}
14251438
infer::EarlyBoundRegion(_, name) => {
1426-
format!(" for lifetime parameter `{}",
1439+
format!(" for lifetime parameter `{}`",
14271440
token::get_name(name).get())
14281441
}
14291442
infer::BoundRegionInCoherence(name) => {
1430-
format!(" for lifetime parameter `{} in coherence check",
1443+
format!(" for lifetime parameter `{}` in coherence check",
14311444
token::get_name(name).get())
14321445
}
14331446
infer::UpvarRegion(ref upvar_id, _) => {
@@ -1528,6 +1541,15 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
15281541
self.tcx,
15291542
id).get().to_string()).as_slice());
15301543
}
1544+
infer::ProcCapture(span, id) => {
1545+
self.tcx.sess.span_note(
1546+
span,
1547+
format!("...so that captured variable `{}` \
1548+
is 'static",
1549+
ty::local_var_name_str(
1550+
self.tcx,
1551+
id).get()).as_slice());
1552+
}
15311553
infer::IndexSlice(span) => {
15321554
self.tcx.sess.span_note(
15331555
span,
@@ -1571,8 +1593,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
15711593
infer::AutoBorrow(span) => {
15721594
self.tcx.sess.span_note(
15731595
span,
1574-
"...so that reference is valid \
1575-
at the time of implicit borrow");
1596+
"...so that auto-reference is valid \
1597+
at the time of borrow");
15761598
}
15771599
infer::ExprTypeIsNotInScope(t, span) => {
15781600
self.tcx.sess.span_note(

src/librustc/middle/typeck/infer/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ pub enum SubregionOrigin {
161161
// Closure bound must not outlive captured free variables
162162
FreeVariable(Span, ast::NodeId),
163163

164+
// Proc upvars must be 'static
165+
ProcCapture(Span, ast::NodeId),
166+
164167
// Index into slice must be within its lifetime
165168
IndexSlice(Span),
166169

@@ -933,6 +936,7 @@ impl SubregionOrigin {
933936
InvokeClosure(a) => a,
934937
DerefPointer(a) => a,
935938
FreeVariable(a, _) => a,
939+
ProcCapture(a, _) => a,
936940
IndexSlice(a) => a,
937941
RelateObjectBound(a) => a,
938942
RelateProcBound(a, _, _) => a,
@@ -972,6 +976,9 @@ impl Repr for SubregionOrigin {
972976
FreeVariable(a, b) => {
973977
format!("FreeVariable({}, {})", a.repr(tcx), b)
974978
}
979+
ProcCapture(a, b) => {
980+
format!("ProcCapture({}, {})", a.repr(tcx), b)
981+
}
975982
IndexSlice(a) => {
976983
format!("IndexSlice({})", a.repr(tcx))
977984
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that, when a variable of type `&T` is captured inside a proc,
12+
// we correctly infer/require that its lifetime is 'static.
13+
14+
fn foo(_p: proc():'static) { }
15+
16+
static i: int = 3;
17+
18+
fn capture_local() {
19+
let x = 3i;
20+
let y = &x; //~ ERROR `x` does not live long enough
21+
foo(proc() {
22+
let _a = *y;
23+
});
24+
}
25+
26+
fn capture_static() {
27+
// Legal because &i can have static lifetime:
28+
let y = &i;
29+
foo(proc() {
30+
let _a = *y;
31+
});
32+
}
33+
34+
fn main() { }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that the 'static bound on a proc influences lifetimes of
12+
// region variables contained within (otherwise, region inference will
13+
// give `x` a very short lifetime).
14+
15+
static i: uint = 3;
16+
fn foo(_: proc():'static) {}
17+
fn read(_: uint) { }
18+
pub fn main() {
19+
let x = &i;
20+
foo(proc() {
21+
read(*x);
22+
});
23+
}

0 commit comments

Comments
 (0)