about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-07-22 05:27:46 -0400
committerNiko Matsakis <niko@alum.mit.edu>2014-08-28 14:15:32 -0400
commitf60a7c4798e0c7e7b2c6814eb55b35f4b4769fe2 (patch)
treeeacce78b70d64ad1d0d4d9bee9830fc41452346c
parentb5165321e48c1fd8422803fb40693afab7939c8c (diff)
downloadrust-f60a7c4798e0c7e7b2c6814eb55b35f4b4769fe2.tar.gz
rust-f60a7c4798e0c7e7b2c6814eb55b35f4b4769fe2.zip
Fix regionck to consider bounds on a proc when capturing variables
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs6
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs30
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs7
-rw-r--r--src/test/compile-fail/regions-infer-proc-static-upvar.rs34
-rw-r--r--src/test/run-pass/regions-infer-static-from-proc.rs23
5 files changed, 96 insertions, 4 deletions
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 72f33a2f984..e7676301946 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -1534,6 +1534,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
 
 fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
                                     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;
     loop {
         debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index 2883a960df9..bd355d2f580 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -583,6 +583,19 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
                     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) => {
                 self.tcx.sess.span_err(span,
                                        "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))
             }
             infer::EarlyBoundRegion(_, name) => {
-                format!(" for lifetime parameter `{}",
+                format!(" for lifetime parameter `{}`",
                         token::get_name(name).get())
             }
             infer::BoundRegionInCoherence(name) => {
-                format!(" for lifetime parameter `{} in coherence check",
+                format!(" for lifetime parameter `{}` in coherence check",
                         token::get_name(name).get())
             }
             infer::UpvarRegion(ref upvar_id, _) => {
@@ -1528,6 +1541,15 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
                                 self.tcx,
                                 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) => {
                 self.tcx.sess.span_note(
                     span,
@@ -1571,8 +1593,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
             infer::AutoBorrow(span) => {
                 self.tcx.sess.span_note(
                     span,
-                    "...so that reference is valid \
-                     at the time of implicit borrow");
+                    "...so that auto-reference is valid \
+                     at the time of borrow");
             }
             infer::ExprTypeIsNotInScope(t, span) => {
                 self.tcx.sess.span_note(
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index ed96effdd83..c6312ec4663 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -161,6 +161,9 @@ pub enum SubregionOrigin {
     // Closure bound must not outlive captured free variables
     FreeVariable(Span, ast::NodeId),
 
+    // Proc upvars must be 'static
+    ProcCapture(Span, ast::NodeId),
+
     // Index into slice must be within its lifetime
     IndexSlice(Span),
 
@@ -933,6 +936,7 @@ impl SubregionOrigin {
             InvokeClosure(a) => a,
             DerefPointer(a) => a,
             FreeVariable(a, _) => a,
+            ProcCapture(a, _) => a,
             IndexSlice(a) => a,
             RelateObjectBound(a) => a,
             RelateProcBound(a, _, _) => a,
@@ -972,6 +976,9 @@ impl Repr for SubregionOrigin {
             FreeVariable(a, b) => {
                 format!("FreeVariable({}, {})", a.repr(tcx), b)
             }
+            ProcCapture(a, b) => {
+                format!("ProcCapture({}, {})", a.repr(tcx), b)
+            }
             IndexSlice(a) => {
                 format!("IndexSlice({})", a.repr(tcx))
             }
diff --git a/src/test/compile-fail/regions-infer-proc-static-upvar.rs b/src/test/compile-fail/regions-infer-proc-static-upvar.rs
new file mode 100644
index 00000000000..7fe85290da0
--- /dev/null
+++ b/src/test/compile-fail/regions-infer-proc-static-upvar.rs
@@ -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() { }
diff --git a/src/test/run-pass/regions-infer-static-from-proc.rs b/src/test/run-pass/regions-infer-static-from-proc.rs
new file mode 100644
index 00000000000..823644ddfb5
--- /dev/null
+++ b/src/test/run-pass/regions-infer-static-from-proc.rs
@@ -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);
+    });
+}