about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-23 00:16:28 -0700
committerbors <bors@rust-lang.org>2013-08-23 00:16:28 -0700
commit5e5e2c71e403371ff8a5d5430e7696654214a438 (patch)
tree25ca443f4dd0b513202ddf00a4ad53515f8b184c /src
parent0688bde47f1288eec730a3e01dcbf825900db3c0 (diff)
parent0081961c57494162d9f2d19265175af95fbdd8d7 (diff)
downloadrust-5e5e2c71e403371ff8a5d5430e7696654214a438.tar.gz
rust-5e5e2c71e403371ff8a5d5430e7696654214a438.zip
auto merge of #8677 : bblum/rust/scratch, r=alexcrichton
r anybody; there isn't anything complicated here
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/resolve.rs10
-rw-r--r--src/libstd/cell.rs6
-rw-r--r--src/libstd/macros.rs36
-rw-r--r--src/libstd/rt/comm.rs13
-rw-r--r--src/libstd/rt/mod.rs1
-rw-r--r--src/libstd/task/spawn.rs77
-rw-r--r--src/test/compile-fail/issue-6642.rs21
7 files changed, 110 insertions, 54 deletions
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 2e8748e4ff8..0dee86e2a19 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -4814,9 +4814,13 @@ impl Resolver {
                                         DontAllowCapturingSelf) {
                         Some(dl_def(def)) => return Some(def),
                         _ => {
-                            self.session.span_bug(span,
-                                                  "self wasn't mapped to a \
-                                                   def?!")
+                            if self.session.has_errors() {
+                                // May happen inside a nested fn item, cf #6642.
+                                return None;
+                            } else {
+                                self.session.span_bug(span,
+                                        "self wasn't mapped to a def?!")
+                            }
                         }
                     }
                 }
diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs
index 5db855d5b3c..f9f5b66acb6 100644
--- a/src/libstd/cell.rs
+++ b/src/libstd/cell.rs
@@ -50,6 +50,12 @@ impl<T> Cell<T> {
         this.value.take_unwrap()
     }
 
+    /// Yields the value if the cell is full, or `None` if it is empty.
+    pub fn take_opt(&self) -> Option<T> {
+        let this = unsafe { transmute_mut(self) };
+        this.value.take()
+    }
+
     /// Returns the value, failing if the cell is full.
     pub fn put_back(&self, value: T) {
         let this = unsafe { transmute_mut(self) };
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 89c7b294512..600d0bb133e 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -40,3 +40,39 @@ macro_rules! rtabort(
     } )
 )
 
+macro_rules! assert_once_ever(
+    ($( $msg:expr),+) => ( {
+        // FIXME(#8472) extra function should not be needed to hide unsafe
+        fn assert_once_ever() {
+            unsafe {
+                static mut already_happened: int = 0;
+                // Double-check lock to avoid a swap in the common case.
+                if already_happened != 0 ||
+                    ::unstable::intrinsics::atomic_xchg_relaxed(&mut already_happened, 1) != 0 {
+                        fail!(fmt!("assert_once_ever happened twice: %s", fmt!($($msg),+)));
+                }
+            }
+        }
+        assert_once_ever();
+    } )
+)
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn test_assert_once_ever_ok() {
+        assert_once_ever!("help i'm stuck in an");
+        assert_once_ever!("assertion error message");
+    }
+
+    #[test] #[ignore(cfg(windows))] #[should_fail]
+    fn test_assert_once_ever_fail() {
+        use task;
+
+        fn f() { assert_once_ever!("if you're seeing this... good!") }
+
+        // linked & watched, naturally
+        task::spawn(f);
+        task::spawn(f);
+    }
+}
diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs
index 5d55261a69d..8ef9c1332f9 100644
--- a/src/libstd/rt/comm.rs
+++ b/src/libstd/rt/comm.rs
@@ -499,13 +499,14 @@ impl<T> GenericPort<T> for Port<T> {
     }
 
     fn try_recv(&self) -> Option<T> {
-        let pone = self.next.take();
-        match pone.try_recv() {
-            Some(StreamPayload { val, next }) => {
-                self.next.put_back(next);
-                Some(val)
+        do self.next.take_opt().map_move_default(None) |pone| {
+            match pone.try_recv() {
+                Some(StreamPayload { val, next }) => {
+                    self.next.put_back(next);
+                    Some(val)
+                }
+                None => None
             }
-            None => None
         }
     }
 }
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index db1bfdf1bf5..8b3e65b57ab 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -323,6 +323,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
     // task tree, shut down the schedulers and set the exit code.
     let handles = Cell::new(handles);
     let on_exit: ~fn(bool) = |exit_success| {
+        assert_once_ever!("last task exiting");
 
         let mut handles = handles.take();
         for handle in handles.mut_iter() {
diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs
index 783d9c3e810..980141d29c3 100644
--- a/src/libstd/task/spawn.rs
+++ b/src/libstd/task/spawn.rs
@@ -446,8 +446,7 @@ fn taskgroup_key() -> local_data::Key<@@mut Taskgroup> {
 // Transitionary.
 struct RuntimeGlue;
 impl RuntimeGlue {
-    fn kill_task(handle: KillHandle) {
-        let mut handle = handle;
+    fn kill_task(mut handle: KillHandle) {
         do handle.kill().map_move |killed_task| {
             let killed_task = Cell::new(killed_task);
             do Local::borrow::<Scheduler, ()> |sched| {
@@ -457,44 +456,38 @@ impl RuntimeGlue {
     }
 
     fn with_task_handle_and_failing(blk: &fn(&KillHandle, bool)) {
-        if in_green_task_context() {
-            unsafe {
-                // Can't use safe borrow, because the taskgroup destructor needs to
-                // access the scheduler again to send kill signals to other tasks.
-                let me = Local::unsafe_borrow::<Task>();
-                blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding)
-            }
-        } else {
-            rtabort!("task dying in bad context")
+        rtassert!(in_green_task_context());
+        unsafe {
+            // Can't use safe borrow, because the taskgroup destructor needs to
+            // access the scheduler again to send kill signals to other tasks.
+            let me = Local::unsafe_borrow::<Task>();
+            blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding)
         }
     }
 
     fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U {
-        if in_green_task_context() {
-            unsafe {
-                // Can't use safe borrow, because creating new hashmaps for the
-                // tasksets requires an rng, which needs to borrow the sched.
-                let me = Local::unsafe_borrow::<Task>();
-                blk(match (*me).taskgroup {
-                    None => {
-                        // First task in its (unlinked/unsupervised) taskgroup.
-                        // Lazily initialize.
-                        let mut members = TaskSet::new();
-                        let my_handle = (*me).death.kill_handle.get_ref().clone();
-                        members.insert(my_handle);
-                        let tasks = Exclusive::new(Some(TaskGroupData {
-                            members: members,
-                            descendants: TaskSet::new(),
-                        }));
-                        let group = Taskgroup(tasks, AncestorList(None), None);
-                        (*me).taskgroup = Some(group);
-                        (*me).taskgroup.get_ref()
-                    }
-                    Some(ref group) => group,
-                })
-            }
-        } else {
-            rtabort!("spawning in bad context")
+        rtassert!(in_green_task_context());
+        unsafe {
+            // Can't use safe borrow, because creating new hashmaps for the
+            // tasksets requires an rng, which needs to borrow the sched.
+            let me = Local::unsafe_borrow::<Task>();
+            blk(match (*me).taskgroup {
+                None => {
+                    // First task in its (unlinked/unsupervised) taskgroup.
+                    // Lazily initialize.
+                    let mut members = TaskSet::new();
+                    let my_handle = (*me).death.kill_handle.get_ref().clone();
+                    members.insert(my_handle);
+                    let tasks = Exclusive::new(Some(TaskGroupData {
+                        members: members,
+                        descendants: TaskSet::new(),
+                    }));
+                    let group = Taskgroup(tasks, AncestorList(None), None);
+                    (*me).taskgroup = Some(group);
+                    (*me).taskgroup.get_ref()
+                }
+                Some(ref group) => group,
+            })
         }
     }
 }
@@ -567,17 +560,11 @@ fn enlist_many(child: &KillHandle, child_arc: &TaskGroupArc,
     result
 }
 
-pub fn spawn_raw(opts: TaskOpts, f: ~fn()) {
-    if in_green_task_context() {
-        spawn_raw_newsched(opts, f)
-    } else {
-        fail!("can't spawn from this context")
-    }
-}
-
-fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
+pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
     use rt::sched::*;
 
+    rtassert!(in_green_task_context());
+
     let child_data = Cell::new(gen_child_taskgroup(opts.linked, opts.supervised));
     let indestructible = opts.indestructible;
 
diff --git a/src/test/compile-fail/issue-6642.rs b/src/test/compile-fail/issue-6642.rs
new file mode 100644
index 00000000000..bffca995b8e
--- /dev/null
+++ b/src/test/compile-fail/issue-6642.rs
@@ -0,0 +1,21 @@
+// Copyright 2013 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.
+
+struct A;
+impl A {
+    fn m(&self) {
+          fn x() {
+              self.m()
+              //~^ ERROR can't capture dynamic environment in a fn item
+              //~^^ ERROR `self` is not allowed in this context
+          }
+    }
+}
+fn main() {}