From dd406365e1a189c4f229e1eba7ba091605e995ef Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Thu, 8 Aug 2013 19:59:08 -0400 Subject: [PATCH 1/4] Add assert_once_ever macro. Close #7748. (fixme cf #8472) --- src/libstd/macros.rs | 36 ++++++++++++++++++++++++++++++++++++ src/libstd/rt/mod.rs | 1 + 2 files changed, 37 insertions(+) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 89c7b294512a..600d0bb133ef 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/mod.rs b/src/libstd/rt/mod.rs index db1bfdf1bf56..8b3e65b57ab7 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() { From b81f5c547c41571be3814ad4b2802f3305e12152 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Tue, 20 Aug 2013 18:39:18 -0400 Subject: [PATCH 2/4] small cleanups in task/spawn.rs --- src/libstd/task/spawn.rs | 77 +++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index e0efc14a8871..b789a6ca9579 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:: |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::(); - 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::(); + blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding) } } fn with_my_taskgroup(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::(); - 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::(); + 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; From 598072afa46d3c4fca7659c49ef3c9dc9f85787e Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Wed, 21 Aug 2013 18:43:50 -0400 Subject: [PATCH 3/4] Don't fail in port.try_recv() the second time. Close #7800. --- src/libstd/cell.rs | 6 ++++++ src/libstd/rt/comm.rs | 13 +++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index 372effad61d3..a3d06378ed45 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -50,6 +50,12 @@ impl Cell { this.value.take_unwrap() } + /// Yields the value if the cell is full, or `None` if it is empty. + pub fn take_opt(&self) -> Option { + 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/rt/comm.rs b/src/libstd/rt/comm.rs index 49cf8c239b7e..c6b87d889796 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -499,13 +499,14 @@ impl GenericPort for Port { } fn try_recv(&self) -> Option { - 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 } } } From 0081961c57494162d9f2d19265175af95fbdd8d7 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Wed, 21 Aug 2013 18:57:07 -0400 Subject: [PATCH 4/4] Only bug on self-not-mapped-to-def if no previous errors were present. Close #6642. --- src/librustc/middle/resolve.rs | 10 +++++++--- src/test/compile-fail/issue-6642.rs | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-6642.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9654bf3fc01f..4a21c0307f26 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4812,9 +4812,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/test/compile-fail/issue-6642.rs b/src/test/compile-fail/issue-6642.rs new file mode 100644 index 000000000000..bffca995b8e3 --- /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 or the MIT license +// , 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() {}