- `begin_unwind` and `fail!` is now generic over any `T: Any + Send`.
- Every value you fail with gets boxed as an `~Any`.
- Because of implementation issues, `&'static str` and `~str` are still
handled specially behind the scenes.
- Changed the big macro source string in libsyntax to a raw string
literal, and enabled doc comments there.
pub use std::clone;
pub use std::condition;
pub use std::cmp;
+ // NOTE: Remove import after next snapshot
+ #[cfg(stage0)]
pub use std::sys;
pub use std::unstable;
pub use std::str;
None => { // not recording borrows
let msg = "borrowed";
do msg.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line);
+ task::begin_unwind_raw(msg_p, file, line);
}
}
Some(borrow_list) => { // recording borrows
}
}
do msg.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line)
+ task::begin_unwind_raw(msg_p, file, line)
}
}
}
if br.box != a || br.file != file || br.line != line {
let err = format!("wrong borrow found, br={:?}", br);
do err.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line)
+ task::begin_unwind_raw(msg_p, file, line)
}
}
borrow_list
use option::{Option, Some, None};
use prelude::*;
use rt::task::Task;
-use rt::task::UnwindReasonLinked;
+use rt::task::UnwindMessageLinked;
use rt::task::{UnwindResult, Failure};
use task::spawn::Taskgroup;
use to_bytes::IterBytes;
}
if !success {
- result = Cell::new(Failure(UnwindReasonLinked));
+ result = Cell::new(Failure(UnwindMessageLinked));
}
}
on_exit(result.take());
/// The task is ending successfully
Success,
- /// The Task is failing with reason `UnwindReason`
- Failure(UnwindReason),
+ /// The Task is failing with reason `UnwindMessage`
+ Failure(UnwindMessage),
}
impl UnwindResult {
/// Represents the cause of a task failure
#[deriving(ToStr)]
-pub enum UnwindReason {
- /// Failed with a string message
- UnwindReasonStr(SendStr),
+pub enum UnwindMessage {
+ // FIXME: #9913 - This variant is not neccessary once Any works properly
+ /// Failed with a static string message
+ UnwindMessageStrStatic(&'static str),
+
+ // FIXME: #9913 - This variant is not neccessary once Any works properly
+ /// Failed with a owned string message
+ UnwindMessageStrOwned(~str),
/// Failed with an `~Any`
- UnwindReasonAny(~Any),
+ UnwindMessageAny(~Any),
/// Failed because of linked failure
- UnwindReasonLinked
+ UnwindMessageLinked
}
pub struct Unwinder {
unwinding: bool,
- cause: Option<UnwindReason>
+ cause: Option<UnwindMessage>
}
impl Unwinder {
}
}
- pub fn begin_unwind(&mut self, cause: UnwindReason) -> ! {
+ pub fn begin_unwind(&mut self, cause: UnwindMessage) -> ! {
#[fixed_stack_segment]; #[inline(never)];
self.unwinding = true;
/// This is the entry point of unwinding for things like lang items and such.
/// The arguments are normally generated by the compiler, and need to
/// have static lifetimes.
-pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! {
+pub fn begin_unwind_raw(msg: *c_char, file: *c_char, line: size_t) -> ! {
use c_str::CString;
use cast::transmute;
let msg = static_char_ptr(msg);
let file = static_char_ptr(file);
- begin_unwind_reason(UnwindReasonStr(msg.into_send_str()), file, line as uint)
+ begin_unwind(msg, file, line as uint)
}
/// This is the entry point of unwinding for fail!() and assert!().
-pub fn begin_unwind_reason(reason: UnwindReason, file: &'static str, line: uint) -> ! {
+pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
+ // Wrap the fail message in a `Any` box for uniform representation.
+ let any = ~msg as ~Any;
+
+ // FIXME: #9913 - This can be changed to be internal to begin_unwind_internal
+ // once Any works properly.
+ // As a workaround, string types need to be special cased right now
+ // because `Any` does not support dynamically querying whether the
+ // type implements a trait yet, so without requiring that every `Any`
+ // also implements `ToStr` there is no way to get a failure message
+ // out of it again during unwinding.
+ let msg = if any.is::<&'static str>() {
+ UnwindMessageStrStatic(*any.move::<&'static str>().unwrap())
+ } else if any.is::<~str>() {
+ UnwindMessageStrOwned(*any.move::<~str>().unwrap())
+ } else {
+ UnwindMessageAny(any)
+ };
+
+ begin_unwind_internal(msg, file, line)
+}
+
+fn begin_unwind_internal(msg: UnwindMessage, file: &'static str, line: uint) -> ! {
use rt::in_green_task_context;
use rt::task::Task;
use rt::local::Local;
let task: *mut Task;
{
- let msg = match reason {
- UnwindReasonStr(ref s) => s.as_slice(),
- UnwindReasonAny(_) => "~Any",
- UnwindReasonLinked => "linked failure",
+ let msg_s = match msg {
+ UnwindMessageAny(_) => "~Any",
+ UnwindMessageLinked => "linked failure",
+ UnwindMessageStrOwned(ref s) => s.as_slice(),
+ UnwindMessageStrStatic(ref s) => s.as_slice(),
};
if !in_green_task_context() {
rterrln!("failed in non-task context at '{}', {}:{}",
- msg, file, line);
+ msg_s, file, line);
intrinsics::abort();
}
// due to mismanagment of its own kill flag, so calling our own
// logger in its current state is a bit of a problem.
- rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line);
+ rterrln!("task '{}' failed at '{}', {}:{}", n, msg_s, file, line);
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}
}
- (*task).unwinder.begin_unwind(reason);
+ (*task).unwinder.begin_unwind(msg);
}
}
#[cfg(test)]
mod test {
+ use super::*;
use rt::test::*;
#[test]
a.next = Some(b);
}
}
+
+ #[test]
+ #[should_fail]
+ fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) }
}
pub mod path;
pub mod rand;
pub mod run;
+// NOTE: Remove module after next snapshot
+#[cfg(stage0)]
pub mod sys;
pub mod cast;
pub mod fmt;
pub use logging;
pub use option;
pub use os;
+ pub use rt;
pub use str;
+ // NOTE: Remove import after next snapshot
+ #[cfg(stage0)]
pub use sys;
pub use to_bytes;
pub use to_str;
//! Misc low level stuff
+// NOTE: Remove this module after an snapshot
+
#[allow(missing_doc)];
use any::Any;
use kinds::Send;
-use rt::task::{UnwindReasonStr, UnwindReasonAny};
use rt::task;
-use send_str::{SendStr, IntoSendStr};
-/// Trait for initiating task failure with a sendable cause.
pub trait FailWithCause {
- /// Fail the current task with `cause`.
fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
}
-impl FailWithCause for ~str {
- fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause.into_send_str()), file, line)
- }
-}
-
-impl FailWithCause for &'static str {
- fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause.into_send_str()), file, line)
- }
-}
-
-impl FailWithCause for SendStr {
- fn fail_with(cause: SendStr, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause), file, line)
- }
-}
-
-impl FailWithCause for ~Any {
- fn fail_with(cause: ~Any, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonAny(cause), file, line)
- }
-}
-
-impl<T: Any + Send + 'static> FailWithCause for ~T {
- fn fail_with(cause: ~T, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonAny(cause as ~Any), file, line)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use any::Any;
- use cast;
- use send_str::IntoSendStr;
-
- #[test]
- fn synthesize_closure() {
- use unstable::raw::Closure;
- unsafe {
- let x = 10;
- let f: &fn(int) -> int = |y| x + y;
-
- assert_eq!(f(20), 30);
-
- let original_closure: Closure = cast::transmute(f);
-
- let actual_function_pointer = original_closure.code;
- let environment = original_closure.env;
-
- let new_closure = Closure {
- code: actual_function_pointer,
- env: environment
- };
-
- let new_f: &fn(int) -> int = cast::transmute(new_closure);
- assert_eq!(new_f(20), 30);
- }
+impl<T: Any + Send> FailWithCause for T {
+ fn fail_with(msg: T, file: &'static str, line: uint) -> ! {
+ task::begin_unwind(msg, file, line)
}
-
- #[test]
- #[should_fail]
- fn fail_static() { FailWithCause::fail_with("cause", file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_send() { FailWithCause::fail_with("cause".into_send_str(), file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_any() { FailWithCause::fail_with(~612_u16 as ~Any, file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_any_wrap() { FailWithCause::fail_with(~413_u16, file!(), line!()) }
}
use result::{Result, Ok, Err};
use rt::in_green_task_context;
use rt::local::Local;
-use rt::task::{UnwindReasonAny, UnwindReasonLinked, UnwindReasonStr};
+use rt::task::{UnwindMessageAny, UnwindMessageLinked};
+use rt::task::{UnwindMessageStrStatic, UnwindMessageStrOwned};
use rt::task::{UnwindResult, Success, Failure};
use send_str::{SendStr, IntoSendStr};
use unstable::finally::Finally;
fn wrap_as_any(res: UnwindResult) -> TaskResult {
match res {
Success => Ok(()),
- Failure(UnwindReasonStr(s)) => Err(~s as ~Any),
- Failure(UnwindReasonAny(a)) => Err(a),
- Failure(UnwindReasonLinked) => Err(~LinkedFailure as ~Any)
+ Failure(UnwindMessageAny(a)) => Err(a),
+ Failure(UnwindMessageLinked) => Err(~LinkedFailure as ~Any),
+ Failure(UnwindMessageStrOwned(s)) => Err(~s as ~Any),
+ Failure(UnwindMessageStrStatic(s)) => Err(~s as ~Any),
}
}
}
#[test]
-fn test_try_fail_cause_static_str() {
+fn test_try_fail_message_static_str() {
match do try {
fail!("static string");
} {
- Err(ref e) if e.is::<SendStr>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = &'static str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.move::<T>().unwrap(), "static string");
+ }
+ Ok(()) => fail!()
}
}
#[test]
-fn test_try_fail_cause_owned_str() {
+fn test_try_fail_message_owned_str() {
match do try {
fail!(~"owned string");
} {
- Err(ref e) if e.is::<SendStr>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = ~str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.move::<T>().unwrap(), ~"owned string");
+ }
+ Ok(()) => fail!()
}
}
#[test]
-fn test_try_fail_cause_any() {
+fn test_try_fail_message_any() {
match do try {
fail!(~413u16 as ~Any);
} {
- Err(ref e) if e.is::<u16>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = ~Any;
+ assert!(e.is::<T>());
+ let any = e.move::<T>().unwrap();
+ assert!(any.is::<u16>());
+ assert_eq!(*any.move::<u16>().unwrap(), 413u16);
+ }
+ Ok(()) => fail!()
}
}
#[ignore(reason = "linked failure")]
#[test]
-fn test_try_fail_cause_linked() {
+fn test_try_fail_message_linked() {
match do try {
do spawn {
fail!()
}
#[test]
-fn test_try_fail_cause_any_wrapped() {
+fn test_try_fail_message_unit_struct() {
struct Juju;
match do try {
- fail!(~Juju)
+ fail!(Juju)
} {
Err(ref e) if e.is::<Juju>() => {}
Err(_) | Ok(()) => fail!()
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown, TaskFromFriend};
use rt::task::{Task, Sched};
-use rt::task::{UnwindReasonLinked, UnwindReasonStr};
+use rt::task::{UnwindMessageLinked, UnwindMessageStrStatic};
use rt::task::{UnwindResult, Success, Failure};
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::{in_green_task_context, new_event_loop, KillHandle};
-use send_str::IntoSendStr;
use task::SingleThreaded;
use task::TaskOpts;
use task::unkillable;
do RuntimeGlue::with_task_handle_and_failing |me, failing| {
if failing {
for x in self.notifier.mut_iter() {
- x.task_result = Some(Failure(UnwindReasonLinked));
+ x.task_result = Some(Failure(UnwindMessageLinked));
}
// Take everybody down with us. After this point, every
// other task in the group will see 'tg' as none, which
notify_chan: chan,
// Un-set above when taskgroup successfully made.
- task_result: Some(Failure(UnwindReasonStr("AutoNotify::new()".into_send_str())))
+ task_result: Some(Failure(UnwindMessageStrStatic("AutoNotify::new()")))
}
}
}
#[cold]
#[lang="fail_"]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
- task::begin_unwind(expr, file, line);
+ task::begin_unwind_raw(expr, file, line);
}
#[cold]
// sure would be nice to have this
// impl<T> Repr<*Vec<T>> for ~[T] {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use cast;
+
+ #[test]
+ fn synthesize_closure() {
+ unsafe {
+ let x = 10;
+ let f: &fn(int) -> int = |y| x + y;
+
+ assert_eq!(f(20), 30);
+
+ let original_closure: Closure = cast::transmute(f);
+
+ let actual_function_pointer = original_closure.code;
+ let environment = original_closure.env;
+
+ let new_closure = Closure {
+ code: actual_function_pointer,
+ env: environment
+ };
+
+ let new_f: &fn(int) -> int = cast::transmute(new_closure);
+ assert_eq!(new_f(20), 30);
+ }
+ }
+}
span,
~[
self.ident_of("std"),
- self.ident_of("sys"),
- self.ident_of("FailWithCause"),
- self.ident_of("fail_with"),
+ self.ident_of("rt"),
+ self.ident_of("task"),
+ self.ident_of("begin_unwind"),
],
~[
self.expr_str(span, msg),
// syntax elements.
pub fn std_macros() -> @str {
- return
-@"mod __std_macros {
+@r#"mod __std_macros {
#[macro_escape];
#[doc(hidden)];
macro_rules! fail(
() => (
- fail!(\"explicit failure\")
+ fail!("explicit failure")
);
- ($fmt:expr) => (
- ::std::sys::FailWithCause::fail_with($fmt, file!(), line!())
+ ($msg:expr) => (
+ ::std::rt::task::begin_unwind($msg, file!(), line!())
);
($fmt:expr, $($arg:tt)*) => (
- ::std::sys::FailWithCause::fail_with(format!($fmt, $($arg)*), file!(), line!())
+ ::std::rt::task::begin_unwind(format!($fmt, $($arg)*), file!(), line!())
)
)
macro_rules! assert(
($cond:expr) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with(
- \"assertion failed: \" + stringify!($cond), file!(), line!())
+ fail!("assertion failed: {:s}", stringify!($cond))
}
};
($cond:expr, $msg:expr) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with($msg, file!(), line!())
+ fail!($msg)
}
};
($cond:expr, $( $arg:expr ),+) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with(format!( $($arg),+ ), file!(), line!())
+ fail!( $($arg),+ )
}
}
)
// check both directions of equality....
if !((*given_val == *expected_val) &&
(*expected_val == *given_val)) {
- fail!(\"assertion failed: `(left == right) && (right == \
- left)` (left: `{:?}`, right: `{:?}`)\",
- *given_val, *expected_val);
+ fail!("assertion failed: `(left == right) && (right == left)` \
+ (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
}
}
)
given_val.approx_eq(&expected_val) &&
expected_val.approx_eq(&given_val)
) {
- fail!(\"left: {:?} does not approximately equal right: {:?}\",
+ fail!("left: {:?} does not approximately equal right: {:?}",
given_val, expected_val);
}
}
given_val.approx_eq_eps(&expected_val, &epsilon_val) &&
expected_val.approx_eq_eps(&given_val, &epsilon_val)
) {
- fail!(\"left: {:?} does not approximately equal right: \
- {:?} with epsilon: {:?}\",
+ fail!("left: {:?} does not approximately equal right: \
+ {:?} with epsilon: {:?}",
given_val, expected_val, epsilon_val);
}
}
)
)
- // FIXME(#6266): change the /* to /** when attributes are supported on macros
- // (Though even then—is it going to work according to the clear intent here?)
- /*
- A utility macro for indicating unreachable code. It will fail if
- executed. This is occasionally useful to put after loops that never
- terminate normally, but instead directly return from a function.
-
- # Example
-
- ```rust
- fn choose_weighted_item(v: &[Item]) -> Item {
- assert!(!v.is_empty());
- let mut so_far = 0u;
- for v.each |item| {
- so_far += item.weight;
- if so_far > 100 {
- return item;
- }
- }
- // The above loop always returns, so we must hint to the
- // type checker that it isn't possible to get down here
- unreachable!();
- }
- ```
-
- */
+ /// A utility macro for indicating unreachable code. It will fail if
+ /// executed. This is occasionally useful to put after loops that never
+ /// terminate normally, but instead directly return from a function.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// fn choose_weighted_item(v: &[Item]) -> Item {
+ /// assert!(!v.is_empty());
+ /// let mut so_far = 0u;
+ /// for item in v.iter() {
+ /// so_far += item.weight;
+ /// if so_far > 100 {
+ /// return item;
+ /// }
+ /// }
+ /// // The above loop always returns, so we must hint to the
+ /// // type checker that it isn't possible to get down here
+ /// unreachable!();
+ /// }
+ /// ```
macro_rules! unreachable (() => (
- fail!(\"internal error: entered unreachable code\");
+ fail!("internal error: entered unreachable code");
))
macro_rules! condition (
)
)
- // externfn! declares a wrapper for an external function.
- // It is intended to be used like:
- //
- // externfn!(#[nolink]
- // fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
- //
- // Due to limitations in the macro parser, this pattern must be
- // implemented with 4 distinct patterns (with attrs / without
- // attrs CROSS with args / without ARGS).
- //
- // Also, this macro grammar allows for any number of return types
- // because I couldn't figure out the syntax to specify at most one.
+ /// externfn! declares a wrapper for an external function.
+ /// It is intended to be used like:
+ ///
+ /// externfn!(#[nolink]
+ /// fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+ ///
+ /// Due to limitations in the macro parser, this pattern must be
+ /// implemented with 4 distinct patterns (with attrs / without
+ /// attrs CROSS with args / without ARGS).
+ ///
+ /// Also, this macro grammar allows for any number of return types
+ /// because I couldn't figure out the syntax to specify at most one.
macro_rules! externfn(
(fn $name:ident () $(-> $ret_ty:ty),*) => (
pub unsafe fn $name() $(-> $ret_ty),* {
)
)
-}";
+}"#
}
struct Injector {
+++ /dev/null
-// Copyright 2012 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.
-
-// error-pattern:failed to find an implementation of trait std::sys::FailWithCause for int
-
-fn main() { fail!(5); }
+++ /dev/null
-// Copyright 2012 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.
-
-// error-pattern:failed to find an implementation of trait std::sys::FailWithCause for ~[int]
-fn main() { fail!(~[0i]); }
+++ /dev/null
-// 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.
-
-// error-pattern:failed at 'test-fail-send-str'
-
-fn main() {
- fail!("test-fail-send-str".into_send_str());
-}
let _b = Foo;
};
- let s = x.unwrap_err().move::<SendStr>().unwrap();
+ let s = x.unwrap_err().move::<&'static str>().unwrap();
assert_eq!(s.as_slice(), "This failure should happen.");
}