Skip to content

Assorted small bugfixes. #8677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?!")
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/libstd/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
Expand Down
36 changes: 36 additions & 0 deletions src/libstd/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This presumably breaks if it's used twice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Wait, I see, it's got an inner block so the fn is scoped within it.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, macro hygiene saves the day

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);
}
}
13 changes: 7 additions & 6 deletions src/libstd/rt/comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
77 changes: 32 additions & 45 deletions src/libstd/task/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -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,
})
}
}
}
Expand Down Expand Up @@ -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;

Expand Down
21 changes: 21 additions & 0 deletions src/test/compile-fail/issue-6642.rs
Original file line number Diff line number Diff line change
@@ -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() {}