diff options
| author | bors <bors@rust-lang.org> | 2013-08-23 00:16:28 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-23 00:16:28 -0700 |
| commit | 5e5e2c71e403371ff8a5d5430e7696654214a438 (patch) | |
| tree | 25ca443f4dd0b513202ddf00a4ad53515f8b184c /src | |
| parent | 0688bde47f1288eec730a3e01dcbf825900db3c0 (diff) | |
| parent | 0081961c57494162d9f2d19265175af95fbdd8d7 (diff) | |
| download | rust-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.rs | 10 | ||||
| -rw-r--r-- | src/libstd/cell.rs | 6 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 36 | ||||
| -rw-r--r-- | src/libstd/rt/comm.rs | 13 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/task/spawn.rs | 77 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-6642.rs | 21 |
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() {} |
