Fix regionck to consider bounds on a proc when capturing variables
This commit is contained in:
parent
b5165321e4
commit
f60a7c4798
5 changed files with 96 additions and 4 deletions
|
@ -1534,6 +1534,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
|
||||||
|
|
||||||
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
|
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
|
||||||
cmt: mc::cmt) {
|
cmt: mc::cmt) {
|
||||||
|
/*!
|
||||||
|
* Indicates that `cmt` is being directly mutated (e.g., assigned
|
||||||
|
* to). If cmt contains any by-ref upvars, this implies that
|
||||||
|
* those upvars must be borrowed using an `&mut` borow.
|
||||||
|
*/
|
||||||
|
|
||||||
let mut cmt = cmt;
|
let mut cmt = cmt;
|
||||||
loop {
|
loop {
|
||||||
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
|
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
|
||||||
|
|
|
@ -583,6 +583,19 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
infer::ProcCapture(span, id) => {
|
||||||
|
self.tcx.sess.span_err(
|
||||||
|
span,
|
||||||
|
format!("captured variable `{}` must be 'static \
|
||||||
|
to be captured in a proc",
|
||||||
|
ty::local_var_name_str(self.tcx, id).get())
|
||||||
|
.as_slice());
|
||||||
|
note_and_explain_region(
|
||||||
|
self.tcx,
|
||||||
|
"captured variable is only valid for ",
|
||||||
|
sup,
|
||||||
|
"");
|
||||||
|
}
|
||||||
infer::IndexSlice(span) => {
|
infer::IndexSlice(span) => {
|
||||||
self.tcx.sess.span_err(span,
|
self.tcx.sess.span_err(span,
|
||||||
"index of slice outside its lifetime");
|
"index of slice outside its lifetime");
|
||||||
|
@ -1423,11 +1436,11 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
|
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
|
||||||
}
|
}
|
||||||
infer::EarlyBoundRegion(_, name) => {
|
infer::EarlyBoundRegion(_, name) => {
|
||||||
format!(" for lifetime parameter `{}",
|
format!(" for lifetime parameter `{}`",
|
||||||
token::get_name(name).get())
|
token::get_name(name).get())
|
||||||
}
|
}
|
||||||
infer::BoundRegionInCoherence(name) => {
|
infer::BoundRegionInCoherence(name) => {
|
||||||
format!(" for lifetime parameter `{} in coherence check",
|
format!(" for lifetime parameter `{}` in coherence check",
|
||||||
token::get_name(name).get())
|
token::get_name(name).get())
|
||||||
}
|
}
|
||||||
infer::UpvarRegion(ref upvar_id, _) => {
|
infer::UpvarRegion(ref upvar_id, _) => {
|
||||||
|
@ -1528,6 +1541,15 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
self.tcx,
|
self.tcx,
|
||||||
id).get().to_string()).as_slice());
|
id).get().to_string()).as_slice());
|
||||||
}
|
}
|
||||||
|
infer::ProcCapture(span, id) => {
|
||||||
|
self.tcx.sess.span_note(
|
||||||
|
span,
|
||||||
|
format!("...so that captured variable `{}` \
|
||||||
|
is 'static",
|
||||||
|
ty::local_var_name_str(
|
||||||
|
self.tcx,
|
||||||
|
id).get()).as_slice());
|
||||||
|
}
|
||||||
infer::IndexSlice(span) => {
|
infer::IndexSlice(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
|
@ -1571,8 +1593,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||||
infer::AutoBorrow(span) => {
|
infer::AutoBorrow(span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
"...so that reference is valid \
|
"...so that auto-reference is valid \
|
||||||
at the time of implicit borrow");
|
at the time of borrow");
|
||||||
}
|
}
|
||||||
infer::ExprTypeIsNotInScope(t, span) => {
|
infer::ExprTypeIsNotInScope(t, span) => {
|
||||||
self.tcx.sess.span_note(
|
self.tcx.sess.span_note(
|
||||||
|
|
|
@ -161,6 +161,9 @@ pub enum SubregionOrigin {
|
||||||
// Closure bound must not outlive captured free variables
|
// Closure bound must not outlive captured free variables
|
||||||
FreeVariable(Span, ast::NodeId),
|
FreeVariable(Span, ast::NodeId),
|
||||||
|
|
||||||
|
// Proc upvars must be 'static
|
||||||
|
ProcCapture(Span, ast::NodeId),
|
||||||
|
|
||||||
// Index into slice must be within its lifetime
|
// Index into slice must be within its lifetime
|
||||||
IndexSlice(Span),
|
IndexSlice(Span),
|
||||||
|
|
||||||
|
@ -933,6 +936,7 @@ impl SubregionOrigin {
|
||||||
InvokeClosure(a) => a,
|
InvokeClosure(a) => a,
|
||||||
DerefPointer(a) => a,
|
DerefPointer(a) => a,
|
||||||
FreeVariable(a, _) => a,
|
FreeVariable(a, _) => a,
|
||||||
|
ProcCapture(a, _) => a,
|
||||||
IndexSlice(a) => a,
|
IndexSlice(a) => a,
|
||||||
RelateObjectBound(a) => a,
|
RelateObjectBound(a) => a,
|
||||||
RelateProcBound(a, _, _) => a,
|
RelateProcBound(a, _, _) => a,
|
||||||
|
@ -972,6 +976,9 @@ impl Repr for SubregionOrigin {
|
||||||
FreeVariable(a, b) => {
|
FreeVariable(a, b) => {
|
||||||
format!("FreeVariable({}, {})", a.repr(tcx), b)
|
format!("FreeVariable({}, {})", a.repr(tcx), b)
|
||||||
}
|
}
|
||||||
|
ProcCapture(a, b) => {
|
||||||
|
format!("ProcCapture({}, {})", a.repr(tcx), b)
|
||||||
|
}
|
||||||
IndexSlice(a) => {
|
IndexSlice(a) => {
|
||||||
format!("IndexSlice({})", a.repr(tcx))
|
format!("IndexSlice({})", a.repr(tcx))
|
||||||
}
|
}
|
||||||
|
|
34
src/test/compile-fail/regions-infer-proc-static-upvar.rs
Normal file
34
src/test/compile-fail/regions-infer-proc-static-upvar.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that, when a variable of type `&T` is captured inside a proc,
|
||||||
|
// we correctly infer/require that its lifetime is 'static.
|
||||||
|
|
||||||
|
fn foo(_p: proc():'static) { }
|
||||||
|
|
||||||
|
static i: int = 3;
|
||||||
|
|
||||||
|
fn capture_local() {
|
||||||
|
let x = 3i;
|
||||||
|
let y = &x; //~ ERROR `x` does not live long enough
|
||||||
|
foo(proc() {
|
||||||
|
let _a = *y;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capture_static() {
|
||||||
|
// Legal because &i can have static lifetime:
|
||||||
|
let y = &i;
|
||||||
|
foo(proc() {
|
||||||
|
let _a = *y;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
23
src/test/run-pass/regions-infer-static-from-proc.rs
Normal file
23
src/test/run-pass/regions-infer-static-from-proc.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that the 'static bound on a proc influences lifetimes of
|
||||||
|
// region variables contained within (otherwise, region inference will
|
||||||
|
// give `x` a very short lifetime).
|
||||||
|
|
||||||
|
static i: uint = 3;
|
||||||
|
fn foo(_: proc():'static) {}
|
||||||
|
fn read(_: uint) { }
|
||||||
|
pub fn main() {
|
||||||
|
let x = &i;
|
||||||
|
foo(proc() {
|
||||||
|
read(*x);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue