Skip to content

Commit e4271ca

Browse files
committed
core: Add a limited implementation of failure
This adds an small of failure to libcore, hamstrung by the fact that std::fmt hasn't been migrated yet. A few asserts were re-worked to not use std::fmt features, but these asserts can go back to their original form once std::fmt has migrated. The current failure implementation is to just have some symbols exposed by std::rt::unwind that are linked against by libcore. This is an explicit circular dependency, unfortunately. This will be officially supported in the future through compiler support with much nicer failure messages. Additionally, there are two depended-upon symbols today, but in the future there will only be one (once std::fmt has migrated).
1 parent 4686cf2 commit e4271ca

File tree

8 files changed

+155
-77
lines changed

8 files changed

+155
-77
lines changed

src/libcore/char.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ pub fn is_digit_radix(c: char, radix: uint) -> bool {
214214
#[inline]
215215
pub fn to_digit(c: char, radix: uint) -> Option<uint> {
216216
if radix > 36 {
217-
fail!("to_digit: radix {} is too high (maximum 36)", radix);
217+
fail!("to_digit: radix is too high (maximum 36)");
218218
}
219219
let val = match c {
220220
'0' .. '9' => c as uint - ('0' as uint),
@@ -273,7 +273,7 @@ pub fn to_lowercase(c: char) -> char {
273273
#[inline]
274274
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
275275
if radix > 36 {
276-
fail!("from_digit: radix {} is to high (maximum 36)", num);
276+
fail!("from_digit: radix is to high (maximum 36)");
277277
}
278278
if num < radix {
279279
unsafe {

src/libcore/failure.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Failure support for libcore
12+
13+
#![allow(dead_code)]
14+
15+
use str::raw::c_str_to_static_slice;
16+
17+
// FIXME: Once std::fmt is in libcore, all of these functions should delegate
18+
// to a common failure function with this signature:
19+
//
20+
// extern {
21+
// fn rust_unwind(f: &fmt::Arguments, file: &str, line: uint) -> !;
22+
// }
23+
//
24+
// Each of these functions can create a temporary fmt::Arguments
25+
// structure to pass to this function.
26+
27+
#[cold] #[inline(never)] // this is the slow path, always
28+
#[lang="fail_"]
29+
#[cfg(not(test))]
30+
fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
31+
unsafe {
32+
let expr = c_str_to_static_slice(expr as *i8);
33+
let file = c_str_to_static_slice(file as *i8);
34+
begin_unwind(expr, file, line)
35+
}
36+
}
37+
38+
#[cold]
39+
#[lang="fail_bounds_check"]
40+
#[cfg(not(test))]
41+
fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
42+
#[allow(ctypes)]
43+
extern { fn rust_fail_bounds_check(file: *u8, line: uint,
44+
index: uint, len: uint,) -> !; }
45+
unsafe { rust_fail_bounds_check(file, line, index, len) }
46+
}
47+
48+
#[cold]
49+
pub fn begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
50+
#[allow(ctypes)]
51+
extern { fn rust_begin_unwind(msg: &str, file: &'static str,
52+
line: uint) -> !; }
53+
unsafe { rust_begin_unwind(msg, file, line) }
54+
}

src/libcore/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#![feature(globs, macro_rules, managed_boxes)]
2222
#![deny(missing_doc)]
2323

24+
mod macros;
25+
2426
#[path = "num/float_macros.rs"] mod float_macros;
2527
#[path = "num/int_macros.rs"] mod int_macros;
2628
#[path = "num/uint_macros.rs"] mod uint_macros;
@@ -75,7 +77,11 @@ pub mod slice;
7577
pub mod str;
7678
pub mod tuple;
7779

78-
// FIXME: this module should not exist
80+
mod failure;
81+
82+
// FIXME: this module should not exist. Once owned allocations are no longer a
83+
// language type, this module can move outside to the owned allocation
84+
// crate.
7985
mod should_not_exist;
8086

8187
mod std {

src/libcore/macros.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![macro_escape]
12+
13+
/// Entry point of failure, for details, see std::macros
14+
#[macro_export]
15+
macro_rules! fail(
16+
() => (
17+
fail!("explicit failure")
18+
);
19+
($msg:expr) => (
20+
::failure::begin_unwind($msg, file!(), line!())
21+
);
22+
)
23+
24+
/// Runtime assertion, for details see std::macros
25+
#[macro_export]
26+
macro_rules! assert(
27+
($cond:expr) => (
28+
if !$cond {
29+
fail!(concat!("assertion failed: ", stringify!($cond)))
30+
}
31+
);
32+
)
33+
34+
/// Runtime assertion, disableable at compile time
35+
#[macro_export]
36+
macro_rules! debug_assert(
37+
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
38+
)

src/libcore/num/int_macros.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ mod tests {
255255
fn test_overflows() {
256256
assert!(MAX > 0);
257257
assert!(MIN <= 0);
258-
assert_eq!(MIN + MAX + 1, 0);
258+
assert!(MIN + MAX + 1 == 0);
259259
}
260260

261261
#[test]
@@ -265,25 +265,25 @@ mod tests {
265265

266266
#[test]
267267
pub fn test_abs() {
268-
assert_eq!((1 as $T).abs(), 1 as $T);
269-
assert_eq!((0 as $T).abs(), 0 as $T);
270-
assert_eq!((-1 as $T).abs(), 1 as $T);
268+
assert!((1 as $T).abs() == 1 as $T);
269+
assert!((0 as $T).abs() == 0 as $T);
270+
assert!((-1 as $T).abs() == 1 as $T);
271271
}
272272

273273
#[test]
274274
fn test_abs_sub() {
275-
assert_eq!((-1 as $T).abs_sub(&(1 as $T)), 0 as $T);
276-
assert_eq!((1 as $T).abs_sub(&(1 as $T)), 0 as $T);
277-
assert_eq!((1 as $T).abs_sub(&(0 as $T)), 1 as $T);
278-
assert_eq!((1 as $T).abs_sub(&(-1 as $T)), 2 as $T);
275+
assert!((-1 as $T).abs_sub(&(1 as $T)) == 0 as $T);
276+
assert!((1 as $T).abs_sub(&(1 as $T)) == 0 as $T);
277+
assert!((1 as $T).abs_sub(&(0 as $T)) == 1 as $T);
278+
assert!((1 as $T).abs_sub(&(-1 as $T)) == 2 as $T);
279279
}
280280

281281
#[test]
282282
fn test_signum() {
283-
assert_eq!((1 as $T).signum(), 1 as $T);
284-
assert_eq!((0 as $T).signum(), 0 as $T);
285-
assert_eq!((-0 as $T).signum(), 0 as $T);
286-
assert_eq!((-1 as $T).signum(), -1 as $T);
283+
assert!((1 as $T).signum() == 1 as $T);
284+
assert!((0 as $T).signum() == 0 as $T);
285+
assert!((-0 as $T).signum() == 0 as $T);
286+
assert!((-1 as $T).signum() == -1 as $T);
287287
}
288288

289289
#[test]
@@ -304,33 +304,33 @@ mod tests {
304304

305305
#[test]
306306
fn test_bitwise() {
307-
assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(&(0b1010 as $T)));
308-
assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(&(0b1010 as $T)));
309-
assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(&(0b1010 as $T)));
310-
assert_eq!(0b1110 as $T, (0b0111 as $T).shl(&(1 as $T)));
311-
assert_eq!(0b0111 as $T, (0b1110 as $T).shr(&(1 as $T)));
312-
assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
307+
assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T)));
308+
assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T)));
309+
assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T)));
310+
assert!(0b1110 as $T == (0b0111 as $T).shl(&(1 as $T)));
311+
assert!(0b0111 as $T == (0b1110 as $T).shr(&(1 as $T)));
312+
assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not());
313313
}
314314

315315
#[test]
316316
fn test_count_ones() {
317-
assert_eq!((0b0101100 as $T).count_ones(), 3);
318-
assert_eq!((0b0100001 as $T).count_ones(), 2);
319-
assert_eq!((0b1111001 as $T).count_ones(), 5);
317+
assert!((0b0101100 as $T).count_ones() == 3);
318+
assert!((0b0100001 as $T).count_ones() == 2);
319+
assert!((0b1111001 as $T).count_ones() == 5);
320320
}
321321

322322
#[test]
323323
fn test_count_zeros() {
324-
assert_eq!((0b0101100 as $T).count_zeros(), BITS as $T - 3);
325-
assert_eq!((0b0100001 as $T).count_zeros(), BITS as $T - 2);
326-
assert_eq!((0b1111001 as $T).count_zeros(), BITS as $T - 5);
324+
assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3);
325+
assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2);
326+
assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5);
327327
}
328328

329329
#[test]
330330
fn test_signed_checked_div() {
331-
assert_eq!(10i.checked_div(&2), Some(5));
332-
assert_eq!(5i.checked_div(&0), None);
333-
assert_eq!(int::MIN.checked_div(&-1), None);
331+
assert!(10i.checked_div(&2) == Some(5));
332+
assert!(5i.checked_div(&0) == None);
333+
assert!(int::MIN.checked_div(&-1) == None);
334334
}
335335
}
336336

src/libcore/num/uint_macros.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ mod tests {
192192
fn test_overflows() {
193193
assert!(MAX > 0);
194194
assert!(MIN <= 0);
195-
assert_eq!(MIN + MAX + 1, 0);
195+
assert!(MIN + MAX + 1 == 0);
196196
}
197197

198198
#[test]
@@ -202,32 +202,32 @@ mod tests {
202202

203203
#[test]
204204
fn test_bitwise() {
205-
assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(&(0b1010 as $T)));
206-
assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(&(0b1010 as $T)));
207-
assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(&(0b1010 as $T)));
208-
assert_eq!(0b1110 as $T, (0b0111 as $T).shl(&(1 as $T)));
209-
assert_eq!(0b0111 as $T, (0b1110 as $T).shr(&(1 as $T)));
210-
assert_eq!(MAX - (0b1011 as $T), (0b1011 as $T).not());
205+
assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T)));
206+
assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T)));
207+
assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T)));
208+
assert!(0b1110 as $T == (0b0111 as $T).shl(&(1 as $T)));
209+
assert!(0b0111 as $T == (0b1110 as $T).shr(&(1 as $T)));
210+
assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not());
211211
}
212212

213213
#[test]
214214
fn test_count_ones() {
215-
assert_eq!((0b0101100 as $T).count_ones(), 3);
216-
assert_eq!((0b0100001 as $T).count_ones(), 2);
217-
assert_eq!((0b1111001 as $T).count_ones(), 5);
215+
assert!((0b0101100 as $T).count_ones() == 3);
216+
assert!((0b0100001 as $T).count_ones() == 2);
217+
assert!((0b1111001 as $T).count_ones() == 5);
218218
}
219219

220220
#[test]
221221
fn test_count_zeros() {
222-
assert_eq!((0b0101100 as $T).count_zeros(), BITS as $T - 3);
223-
assert_eq!((0b0100001 as $T).count_zeros(), BITS as $T - 2);
224-
assert_eq!((0b1111001 as $T).count_zeros(), BITS as $T - 5);
222+
assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3);
223+
assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2);
224+
assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5);
225225
}
226226

227227
#[test]
228228
fn test_unsigned_checked_div() {
229-
assert_eq!(10u.checked_div(&2), Some(5));
230-
assert_eq!(5u.checked_div(&0), None);
229+
assert!(10u.checked_div(&2) == Some(5));
230+
assert!(5u.checked_div(&0) == None);
231231
}
232232
}
233233

src/libstd/rt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ use self::task::{Task, BlockedTask};
7070
pub use self::util::default_sched_threads;
7171

7272
// Export unwinding facilities used by the failure macros
73-
pub use self::unwind::{begin_unwind, begin_unwind_raw, begin_unwind_fmt};
73+
pub use self::unwind::{begin_unwind, begin_unwind_fmt};
7474

7575
pub use self::util::{Stdio, Stdout, Stderr};
7676

src/libstd/rt/unwind.rs

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
// Currently Rust uses unwind runtime provided by libgcc.
5959

6060
use any::{Any, AnyRefExt};
61-
use c_str::CString;
6261
use cast;
6362
use fmt;
6463
use kinds::Send;
@@ -298,42 +297,23 @@ pub mod eabi {
298297
}
299298

300299
#[cold]
301-
#[lang="fail_"]
300+
#[no_mangle]
302301
#[cfg(not(test))]
303-
pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
304-
begin_unwind_raw(expr, file, line);
305-
}
306-
307-
#[cold]
308-
#[lang="fail_bounds_check"]
309-
#[cfg(not(test))]
310-
pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
311-
use c_str::ToCStr;
302+
pub extern fn rust_fail_bounds_check(file: *u8, line: uint,
303+
index: uint, len: uint) -> ! {
304+
use str::raw::c_str_to_static_slice;
312305

313306
let msg = format!("index out of bounds: the len is {} but the index is {}",
314307
len as uint, index as uint);
315-
msg.with_c_str(|buf| fail_(buf as *u8, file, line))
308+
begin_unwind(msg, unsafe { c_str_to_static_slice(file as *i8) }, line)
316309
}
317310

318-
/// This is the entry point of unwinding for things like lang items and such.
319-
/// The arguments are normally generated by the compiler, and need to
320-
/// have static lifetimes.
321-
#[inline(never)] #[cold] // this is the slow path, please never inline this
322-
pub fn begin_unwind_raw(msg: *u8, file: *u8, line: uint) -> ! {
323-
use libc::c_char;
324-
#[inline]
325-
fn static_char_ptr(p: *u8) -> &'static str {
326-
let s = unsafe { CString::new(p as *c_char, false) };
327-
match s.as_str() {
328-
Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
329-
None => rtabort!("message wasn't utf8?")
330-
}
331-
}
332-
333-
let msg = static_char_ptr(msg);
334-
let file = static_char_ptr(file);
335-
336-
begin_unwind(msg, file, line as uint)
311+
// Entry point of failure from the libcore crate
312+
#[no_mangle]
313+
#[cfg(not(test))]
314+
pub extern fn rust_begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
315+
use str::StrAllocating;
316+
begin_unwind(msg.to_owned(), file, line)
337317
}
338318

339319
/// The entry point for unwinding with a formatted message.

0 commit comments

Comments
 (0)