From 73806ddd0fd91066d7b903a00a080cbadcc04311 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Mon, 15 Sep 2014 19:29:47 -0700 Subject: [PATCH] Use $crate and macro reexport to reduce duplicated code Many of libstd's macros are now re-exported from libcore and libcollections. Their libstd definitions have moved to a macros_stage0 module and can disappear after the next snapshot. Where the two crates had already diverged, I took the libstd versions as they're generally newer and better-tested. See e.g. d3c831b, which was a fix to libstd's assert_eq!() that didn't make it into libcore's. Fixes #16806. --- src/libcollections/lib.rs | 3 + src/libcollections/macros.rs | 12 + src/libcore/fmt/mod.rs | 5 +- src/libcore/lib.rs | 1 + src/libcore/macros.rs | 203 +++++++- src/libstd/collections/hash/set.rs | 4 +- src/libstd/io/buffered.rs | 5 +- src/libstd/lib.rs | 12 +- src/libstd/macros.rs | 217 +-------- src/libstd/macros_stage0.rs | 649 ++++++++++++++++++++++++++ src/libstd/rand/os.rs | 5 +- src/libstd/time/duration.rs | 6 +- src/test/run-pass/vec-macro-no-std.rs | 39 ++ 13 files changed, 915 insertions(+), 246 deletions(-) create mode 100644 src/libstd/macros_stage0.rs create mode 100644 src/test/run-pass/vec-macro-no-std.rs diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index db236795038..27ab791b604 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -51,6 +51,9 @@ pub use string::String; pub use vec::Vec; pub use vec_map::VecMap; +// Needed for the vec! macro +pub use alloc::boxed; + mod macros; pub mod binary_heap; diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index ce4b1e46773..0dbc71269a6 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -11,6 +11,8 @@ #![macro_escape] /// Creates a `std::vec::Vec` containing the arguments. +// NOTE: remove after the next snapshot +#[cfg(stage0)] macro_rules! vec { ($($e:expr),*) => ({ // leading _ to allow empty construction without a warning. @@ -21,3 +23,13 @@ macro_rules! vec { ($($e:expr),+,) => (vec!($($e),+)) } +/// Creates a `Vec` containing the arguments. +#[cfg(not(stage0))] +#[macro_export] +macro_rules! vec { + ($($x:expr),*) => ({ + let xs: $crate::boxed::Box<[_]> = box [$($x),*]; + $crate::slice::SliceExt::into_vec(xs) + }); + ($($x:expr,)*) => (vec![$($x),*]) +} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 102836f8d30..b7c225c276a 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -20,12 +20,15 @@ use mem; use option::Option; use option::Option::{Some, None}; use ops::{Deref, FnOnce}; -use result::Result::{Ok, Err}; +use result::Result::Ok; use result; use slice::SliceExt; use slice; use str::{self, StrExt, Utf8Error}; +// NOTE: for old macros; remove after the next snapshot +#[cfg(stage0)] use result::Result::Err; + pub use self::num::radix; pub use self::num::Radix; pub use self::num::RadixFmt; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d646245510d..0cda2e4a9c6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -130,6 +130,7 @@ mod array; #[doc(hidden)] mod core { pub use panicking; + pub use fmt; } #[doc(hidden)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index e8fbd9d930f..3b21a68a292 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -30,7 +30,26 @@ macro_rules! panic { }); } -/// Runtime assertion, for details see std::macros +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// assert!(true); +/// # fn some_computation() -> bool { true } +/// assert!(some_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` #[macro_export] macro_rules! assert { ($cond:expr) => ( @@ -38,61 +57,197 @@ macro_rules! assert { panic!(concat!("assertion failed: ", stringify!($cond))) } ); - ($cond:expr, $($arg:tt)*) => ( + ($cond:expr, $($arg:expr),+) => ( if !$cond { - panic!($($arg)*) + panic!($($arg),+) } ); } -/// Runtime assertion for equality, for details see std::macros +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// assert_eq!(a, b); +/// ``` #[macro_export] macro_rules! assert_eq { - ($cond1:expr, $cond2:expr) => ({ - let c1 = $cond1; - let c2 = $cond2; - if c1 != c2 || c2 != c1 { - panic!("expressions not equal, left: {}, right: {}", c1, c2); + ($left:expr , $right:expr) => ({ + match (&($left), &($right)) { + (left_val, right_val) => { + // check both directions of equality.... + if !((*left_val == *right_val) && + (*right_val == *left_val)) { + panic!("assertion failed: `(left == right) && (right == left)` \ + (left: `{}`, right: `{}`)", *left_val, *right_val) + } + } } }) } -/// Runtime assertion for equality, only without `--cfg ndebug` -#[macro_export] -macro_rules! debug_assert_eq { - ($($a:tt)*) => ({ - if cfg!(not(ndebug)) { - assert_eq!($($a)*); - } - }) -} - -/// Runtime assertion, disableable at compile time with `--cfg ndebug` +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing +/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for +/// checks that are too expensive to be present in a release build but may be +/// helpful during development. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// debug_assert!(true); +/// # fn some_expensive_computation() -> bool { true } +/// debug_assert!(some_expensive_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// debug_assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` #[macro_export] macro_rules! debug_assert { ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) } -/// Short circuiting evaluation on Err +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by +/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` +/// useful for checks that are too expensive to be present in a release build +/// but may be helpful during development. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// debug_assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert_eq { + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) +} + +#[cfg(stage0)] #[macro_export] macro_rules! try { ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) }) } -/// Writing a formatted string into a writer +/// Short circuiting evaluation on Err +/// +/// `libstd` contains a more general `try!` macro that uses `FromError`. +#[cfg(not(stage0))] +#[macro_export] +macro_rules! try { + ($e:expr) => ({ + use $crate::result::Result::{Ok, Err}; + + match $e { + Ok(e) => e, + Err(e) => return Err(e), + } + }) +} + +/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// # #![allow(unused_must_use)] +/// +/// let mut w = Vec::new(); +/// write!(&mut w, "test"); +/// write!(&mut w, "formatted {}", "arguments"); +/// ``` #[macro_export] macro_rules! write { ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*))) } -/// Writing a formatted string plus a newline into a writer +/// Equivalent to the `write!` macro, except that a newline is appended after +/// the message is written. #[macro_export] +#[stable] macro_rules! writeln { ($dst:expr, $fmt:expr $($arg:tt)*) => ( write!($dst, concat!($fmt, "\n") $($arg)*) ) } +/// A utility macro for indicating unreachable code. +/// +/// This is useful any time that the compiler can't determine that some code is unreachable. For +/// example: +/// +/// * Match arms with guard conditions. +/// * Loops that dynamically terminate. +/// * Iterators that dynamically terminate. +/// +/// # Panics +/// +/// This will always panic. +/// +/// # Examples +/// +/// Match arms: +/// +/// ```rust +/// fn foo(x: Option) { +/// match x { +/// Some(n) if n >= 0 => println!("Some(Non-negative)"), +/// Some(n) if n < 0 => println!("Some(Negative)"), +/// Some(_) => unreachable!(), // compile error if commented out +/// None => println!("None") +/// } +/// } +/// ``` +/// +/// Iterators: +/// +/// ```rust +/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3 +/// for i in std::iter::count(0_u32, 1) { +/// if 3*i < i { panic!("u32 overflow"); } +/// if x < 3*i { return i-1; } +/// } +/// unreachable!(); +/// } +/// ``` #[macro_export] -macro_rules! unreachable { () => (panic!("unreachable code")) } +macro_rules! unreachable { + () => ({ + panic!("internal error: entered unreachable code") + }); + ($msg:expr) => ({ + unreachable!("{}", $msg) + }); + ($fmt:expr, $($arg:tt)*) => ({ + panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) + }); +} +/// A standardised placeholder for marking unfinished code. It panics with the +/// message `"not yet implemented"` when executed. +#[macro_export] +macro_rules! unimplemented { + () => (panic!("not yet implemented")) +} diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b1824db93aa..b1906da4355 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -21,7 +21,9 @@ use hash::{Hash, Hasher, RandomSipHasher}; use iter::{Iterator, IteratorExt, IteratorCloneExt, FromIterator, Map, Chain, Extend}; use ops::{BitOr, BitAnd, BitXor, Sub}; use option::Option::{Some, None, self}; -use result::Result::{Ok, Err}; + +// NOTE: for old macros; remove after the next snapshot +#[cfg(stage0)] use result::Result::{Ok, Err}; use super::map::{self, HashMap, Keys, INITIAL_CAPACITY}; diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index c56acd38e81..0882efde232 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -18,11 +18,14 @@ use iter::ExactSizeIterator; use ops::Drop; use option::Option; use option::Option::{Some, None}; -use result::Result::{Ok, Err}; +use result::Result::Ok; use slice::{SliceExt}; use slice; use vec::Vec; +// NOTE: for old macros; remove after the next snapshot +#[cfg(stage0)] use result::Result::Err; + /// Wraps a Reader and buffers input from it /// /// It can be excessively inefficient to work directly with a `Reader`. For diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 608ad9882b9..eba90d39b4a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -117,13 +117,18 @@ #![reexport_test_harness_main = "test_main"] +#![macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, + unreachable, unimplemented, write, writeln, vec)] + #[cfg(test)] #[phase(plugin, link)] extern crate log; -extern crate alloc; -extern crate unicode; +#[phase(plugin, link)] extern crate core; +#[phase(plugin, link)] extern crate "collections" as core_collections; extern crate "rand" as core_rand; +extern crate alloc; +extern crate unicode; extern crate libc; // Make std testable by not duplicating lang items. See #2912 @@ -167,7 +172,8 @@ pub use unicode::char; /* Exported macros */ -pub mod macros; +#[cfg(stage0)] pub mod macros_stage0; +#[cfg(not(stage0))] pub mod macros; pub mod bitflags; mod rtdeps; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 63fd3209cc0..e833acb968d 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -57,179 +57,6 @@ macro_rules! panic { }); } -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the `panic!` macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// # Example -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// assert!(true); -/// # fn some_computation() -> bool { true } -/// assert!(some_computation()); -/// -/// // assert with a custom message -/// # let x = true; -/// assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; -/// assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -macro_rules! assert { - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr, $($arg:expr),+) => ( - if !$cond { - panic!($($arg),+) - } - ); -} - -/// Asserts that two expressions are equal to each other, testing equality in -/// both directions. -/// -/// On panic, this macro will print the values of the expressions. -/// -/// # Example -/// -/// ``` -/// let a = 3i; -/// let b = 1i + 2i; -/// assert_eq!(a, b); -/// ``` -#[macro_export] -macro_rules! assert_eq { - ($left:expr , $right:expr) => ({ - match (&($left), &($right)) { - (left_val, right_val) => { - // check both directions of equality.... - if !((*left_val == *right_val) && - (*right_val == *left_val)) { - panic!("assertion failed: `(left == right) && (right == left)` \ - (left: `{}`, right: `{}`)", *left_val, *right_val) - } - } - } - }) -} - -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the `panic!` macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing -/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for -/// checks that are too expensive to be present in a release build but may be -/// helpful during development. -/// -/// # Example -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// debug_assert!(true); -/// # fn some_expensive_computation() -> bool { true } -/// debug_assert!(some_expensive_computation()); -/// -/// // assert with a custom message -/// # let x = true; -/// debug_assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; -/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -macro_rules! debug_assert { - ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) -} - -/// Asserts that two expressions are equal to each other, testing equality in -/// both directions. -/// -/// On panic, this macro will print the values of the expressions. -/// -/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by -/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` -/// useful for checks that are too expensive to be present in a release build -/// but may be helpful during development. -/// -/// # Example -/// -/// ``` -/// let a = 3i; -/// let b = 1i + 2i; -/// debug_assert_eq!(a, b); -/// ``` -#[macro_export] -macro_rules! debug_assert_eq { - ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) -} - -/// A utility macro for indicating unreachable code. -/// -/// This is useful any time that the compiler can't determine that some code is unreachable. For -/// example: -/// -/// * Match arms with guard conditions. -/// * Loops that dynamically terminate. -/// * Iterators that dynamically terminate. -/// -/// # Panics -/// -/// This will always panic. -/// -/// # Examples -/// -/// Match arms: -/// -/// ```rust -/// fn foo(x: Option) { -/// match x { -/// Some(n) if n >= 0 => println!("Some(Non-negative)"), -/// Some(n) if n < 0 => println!("Some(Negative)"), -/// Some(_) => unreachable!(), // compile error if commented out -/// None => println!("None") -/// } -/// } -/// ``` -/// -/// Iterators: -/// -/// ```rust -/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3 -/// for i in std::iter::count(0_u32, 1) { -/// if 3*i < i { panic!("u32 overflow"); } -/// if x < 3*i { return i-1; } -/// } -/// unreachable!(); -/// } -/// ``` -#[macro_export] -macro_rules! unreachable { - () => ({ - panic!("internal error: entered unreachable code") - }); - ($msg:expr) => ({ - unreachable!("{}", $msg) - }); - ($fmt:expr, $($arg:tt)*) => ({ - panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) - }); -} - -/// A standardised placeholder for marking unfinished code. It panics with the -/// message `"not yet implemented"` when executed. -#[macro_export] -macro_rules! unimplemented { - () => (panic!("not yet implemented")) -} - /// Use the syntax described in `std::fmt` to create a value of type `String`. /// See `std::fmt` for more information. /// @@ -246,34 +73,6 @@ macro_rules! format { ($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*))) } -/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. -/// See `std::fmt` for more information. -/// -/// # Example -/// -/// ``` -/// # #![allow(unused_must_use)] -/// -/// let mut w = Vec::new(); -/// write!(&mut w, "test"); -/// write!(&mut w, "formatted {}", "arguments"); -/// ``` -#[macro_export] -#[stable] -macro_rules! write { - ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*))) -} - -/// Equivalent to the `write!` macro, except that a newline is appended after -/// the message is written. -#[macro_export] -#[stable] -macro_rules! writeln { - ($dst:expr, $fmt:expr $($arg:tt)*) => ( - write!($dst, concat!($fmt, "\n") $($arg)*) - ) -} - /// Equivalent to the `println!` macro except that a newline is not printed at /// the end of the message. #[macro_export] @@ -306,23 +105,15 @@ macro_rules! println { #[macro_export] macro_rules! try { ($expr:expr) => ({ + use $crate::result::Result::{Ok, Err}; + match $expr { Ok(val) => val, - Err(err) => return Err(::std::error::FromError::from_error(err)) + Err(err) => return Err($crate::error::FromError::from_error(err)), } }) } -/// Create a `std::vec::Vec` containing the arguments. -#[macro_export] -macro_rules! vec { - ($($x:expr),*) => ({ - let xs: ::std::boxed::Box<[_]> = box [$($x),*]; - ::std::slice::SliceExt::into_vec(xs) - }); - ($($x:expr,)*) => (vec![$($x),*]) -} - /// A macro to select an event from a number of receivers. /// /// This macro is used to wait for the first event to occur on a number of @@ -358,7 +149,7 @@ macro_rules! select { ( $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ ) => ({ - use std::sync::mpsc::Select; + use $crate::sync::mpsc::Select; let sel = Select::new(); $( let mut $rx = sel.handle(&$rx); )+ unsafe { diff --git a/src/libstd/macros_stage0.rs b/src/libstd/macros_stage0.rs new file mode 100644 index 00000000000..63fd3209cc0 --- /dev/null +++ b/src/libstd/macros_stage0.rs @@ -0,0 +1,649 @@ +// Copyright 2014 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. + +//! Standard library macros +//! +//! This modules contains a set of macros which are exported from the standard +//! library. Each macro is available for use when linking against the standard +//! library. + +#![experimental] +#![macro_escape] + +/// The entry point for panic of Rust tasks. +/// +/// This macro is used to inject panic into a Rust task, causing the task to +/// unwind and panic entirely. Each task's panic can be reaped as the +/// `Box` type, and the single-argument form of the `panic!` macro will be +/// the value which is transmitted. +/// +/// The multi-argument form of this macro panics with a string and has the +/// `format!` syntax for building a string. +/// +/// # Example +/// +/// ```should_fail +/// # #![allow(unreachable_code)] +/// panic!(); +/// panic!("this is a terrible mistake!"); +/// panic!(4i); // panic with the value of 4 to be collected elsewhere +/// panic!("this is a {} {message}", "fancy", message = "message"); +/// ``` +#[macro_export] +macro_rules! panic { + () => ({ + panic!("explicit panic") + }); + ($msg:expr) => ({ + // static requires less code at runtime, more constant data + static _FILE_LINE: (&'static str, uint) = (file!(), line!()); + ::std::rt::begin_unwind($msg, &_FILE_LINE) + }); + ($fmt:expr, $($arg:tt)*) => ({ + // The leading _'s are to avoid dead code warnings if this is + // used inside a dead function. Just `#[allow(dead_code)]` is + // insufficient, since the user may have + // `#[forbid(dead_code)]` and which cannot be overridden. + static _FILE_LINE: (&'static str, uint) = (file!(), line!()); + ::std::rt::begin_unwind_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE) + + }); +} + +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// assert!(true); +/// # fn some_computation() -> bool { true } +/// assert!(some_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` +#[macro_export] +macro_rules! assert { + ($cond:expr) => ( + if !$cond { + panic!(concat!("assertion failed: ", stringify!($cond))) + } + ); + ($cond:expr, $($arg:expr),+) => ( + if !$cond { + panic!($($arg),+) + } + ); +} + +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! assert_eq { + ($left:expr , $right:expr) => ({ + match (&($left), &($right)) { + (left_val, right_val) => { + // check both directions of equality.... + if !((*left_val == *right_val) && + (*right_val == *left_val)) { + panic!("assertion failed: `(left == right) && (right == left)` \ + (left: `{}`, right: `{}`)", *left_val, *right_val) + } + } + } + }) +} + +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing +/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for +/// checks that are too expensive to be present in a release build but may be +/// helpful during development. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// debug_assert!(true); +/// # fn some_expensive_computation() -> bool { true } +/// debug_assert!(some_expensive_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// debug_assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert { + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) +} + +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by +/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` +/// useful for checks that are too expensive to be present in a release build +/// but may be helpful during development. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// debug_assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert_eq { + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) +} + +/// A utility macro for indicating unreachable code. +/// +/// This is useful any time that the compiler can't determine that some code is unreachable. For +/// example: +/// +/// * Match arms with guard conditions. +/// * Loops that dynamically terminate. +/// * Iterators that dynamically terminate. +/// +/// # Panics +/// +/// This will always panic. +/// +/// # Examples +/// +/// Match arms: +/// +/// ```rust +/// fn foo(x: Option) { +/// match x { +/// Some(n) if n >= 0 => println!("Some(Non-negative)"), +/// Some(n) if n < 0 => println!("Some(Negative)"), +/// Some(_) => unreachable!(), // compile error if commented out +/// None => println!("None") +/// } +/// } +/// ``` +/// +/// Iterators: +/// +/// ```rust +/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3 +/// for i in std::iter::count(0_u32, 1) { +/// if 3*i < i { panic!("u32 overflow"); } +/// if x < 3*i { return i-1; } +/// } +/// unreachable!(); +/// } +/// ``` +#[macro_export] +macro_rules! unreachable { + () => ({ + panic!("internal error: entered unreachable code") + }); + ($msg:expr) => ({ + unreachable!("{}", $msg) + }); + ($fmt:expr, $($arg:tt)*) => ({ + panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) + }); +} + +/// A standardised placeholder for marking unfinished code. It panics with the +/// message `"not yet implemented"` when executed. +#[macro_export] +macro_rules! unimplemented { + () => (panic!("not yet implemented")) +} + +/// Use the syntax described in `std::fmt` to create a value of type `String`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// format!("test"); +/// format!("hello {}", "world!"); +/// format!("x = {}, y = {y}", 10i, y = 30i); +/// ``` +#[macro_export] +#[stable] +macro_rules! format { + ($($arg:tt)*) => (::std::fmt::format(format_args!($($arg)*))) +} + +/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// # #![allow(unused_must_use)] +/// +/// let mut w = Vec::new(); +/// write!(&mut w, "test"); +/// write!(&mut w, "formatted {}", "arguments"); +/// ``` +#[macro_export] +#[stable] +macro_rules! write { + ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*))) +} + +/// Equivalent to the `write!` macro, except that a newline is appended after +/// the message is written. +#[macro_export] +#[stable] +macro_rules! writeln { + ($dst:expr, $fmt:expr $($arg:tt)*) => ( + write!($dst, concat!($fmt, "\n") $($arg)*) + ) +} + +/// Equivalent to the `println!` macro except that a newline is not printed at +/// the end of the message. +#[macro_export] +#[stable] +macro_rules! print { + ($($arg:tt)*) => (::std::io::stdio::print_args(format_args!($($arg)*))) +} + +/// Macro for printing to a task's stdout handle. +/// +/// Each task can override its stdout handle via `std::io::stdio::set_stdout`. +/// The syntax of this macro is the same as that used for `format!`. For more +/// information, see `std::fmt` and `std::io::stdio`. +/// +/// # Example +/// +/// ``` +/// println!("hello there!"); +/// println!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[stable] +macro_rules! println { + ($($arg:tt)*) => (::std::io::stdio::println_args(format_args!($($arg)*))) +} + +/// Helper macro for unwrapping `Result` values while returning early with an +/// error if the value of the expression is `Err`. For more information, see +/// `std::io`. +#[macro_export] +macro_rules! try { + ($expr:expr) => ({ + match $expr { + Ok(val) => val, + Err(err) => return Err(::std::error::FromError::from_error(err)) + } + }) +} + +/// Create a `std::vec::Vec` containing the arguments. +#[macro_export] +macro_rules! vec { + ($($x:expr),*) => ({ + let xs: ::std::boxed::Box<[_]> = box [$($x),*]; + ::std::slice::SliceExt::into_vec(xs) + }); + ($($x:expr,)*) => (vec![$($x),*]) +} + +/// A macro to select an event from a number of receivers. +/// +/// This macro is used to wait for the first event to occur on a number of +/// receivers. It places no restrictions on the types of receivers given to +/// this macro, this can be viewed as a heterogeneous select. +/// +/// # Example +/// +/// ``` +/// use std::thread::Thread; +/// use std::sync::mpsc::channel; +/// +/// let (tx1, rx1) = channel(); +/// let (tx2, rx2) = channel(); +/// # fn long_running_task() {} +/// # fn calculate_the_answer() -> int { 42i } +/// +/// Thread::spawn(move|| { long_running_task(); tx1.send(()) }).detach(); +/// Thread::spawn(move|| { tx2.send(calculate_the_answer()) }).detach(); +/// +/// select! ( +/// _ = rx1.recv() => println!("the long running task finished first"), +/// answer = rx2.recv() => { +/// println!("the answer was: {}", answer.unwrap()); +/// } +/// ) +/// ``` +/// +/// For more information about select, see the `std::sync::mpsc::Select` structure. +#[macro_export] +#[experimental] +macro_rules! select { + ( + $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ + ) => ({ + use std::sync::mpsc::Select; + let sel = Select::new(); + $( let mut $rx = sel.handle(&$rx); )+ + unsafe { + $( $rx.add(); )+ + } + let ret = sel.wait(); + $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ + { unreachable!() } + }) +} + +// When testing the standard library, we link to the liblog crate to get the +// logging macros. In doing so, the liblog crate was linked against the real +// version of libstd, and uses a different std::fmt module than the test crate +// uses. To get around this difference, we redefine the log!() macro here to be +// just a dumb version of what it should be. +#[cfg(test)] +macro_rules! log { + ($lvl:expr, $($args:tt)*) => ( + if log_enabled!($lvl) { println!($($args)*) } + ) +} + +/// Built-in macros to the compiler itself. +/// +/// These macros do not have any corresponding definition with a `macro_rules!` +/// macro, but are documented here. Their implementations can be found hardcoded +/// into libsyntax itself. +#[cfg(dox)] +pub mod builtin { + /// The core macro for formatted string creation & output. + /// + /// This macro produces a value of type `fmt::Arguments`. This value can be + /// passed to the functions in `std::fmt` for performing useful functions. + /// All other formatting macros (`format!`, `write!`, `println!`, etc) are + /// proxied through this one. + /// + /// For more information, see the documentation in `std::fmt`. + /// + /// # Example + /// + /// ```rust + /// use std::fmt; + /// + /// let s = fmt::format(format_args!("hello {}", "world")); + /// assert_eq!(s, format!("hello {}", "world")); + /// + /// ``` + #[macro_export] + macro_rules! format_args { ($fmt:expr $($args:tt)*) => ({ + /* compiler built-in */ + }) } + + /// Inspect an environment variable at compile time. + /// + /// This macro will expand to the value of the named environment variable at + /// compile time, yielding an expression of type `&'static str`. + /// + /// If the environment variable is not defined, then a compilation error + /// will be emitted. To not emit a compile error, use the `option_env!` + /// macro instead. + /// + /// # Example + /// + /// ```rust + /// let path: &'static str = env!("PATH"); + /// println!("the $PATH variable at the time of compiling was: {}", path); + /// ``` + #[macro_export] + macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) } + + /// Optionally inspect an environment variable at compile time. + /// + /// If the named environment variable is present at compile time, this will + /// expand into an expression of type `Option<&'static str>` whose value is + /// `Some` of the value of the environment variable. If the environment + /// variable is not present, then this will expand to `None`. + /// + /// A compile time error is never emitted when using this macro regardless + /// of whether the environment variable is present or not. + /// + /// # Example + /// + /// ```rust + /// let key: Option<&'static str> = option_env!("SECRET_KEY"); + /// println!("the secret key might be: {}", key); + /// ``` + #[macro_export] + macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + + /// Concatenate literals into a static byte slice. + /// + /// This macro takes any number of comma-separated literal expressions, + /// yielding an expression of type `&'static [u8]` which is the + /// concatenation (left to right) of all the literals in their byte format. + /// + /// This extension currently only supports string literals, character + /// literals, and integers less than 256. The byte slice returned is the + /// utf8-encoding of strings and characters. + /// + /// # Example + /// + /// ``` + /// let rust = bytes!("r", 'u', "st", 255); + /// assert_eq!(rust[1], b'u'); + /// assert_eq!(rust[4], 255); + /// ``` + #[macro_export] + macro_rules! bytes { ($($e:expr),*) => ({ /* compiler built-in */ }) } + + /// Concatenate identifiers into one identifier. + /// + /// This macro takes any number of comma-separated identifiers, and + /// concatenates them all into one, yielding an expression which is a new + /// identifier. Note that hygiene makes it such that this macro cannot + /// capture local variables, and macros are only allowed in item, + /// statement or expression position, meaning this macro may be difficult to + /// use in some situations. + /// + /// # Example + /// + /// ``` + /// #![feature(concat_idents)] + /// + /// # fn main() { + /// fn foobar() -> int { 23 } + /// + /// let f = concat_idents!(foo, bar); + /// println!("{}", f()); + /// # } + /// ``` + #[macro_export] + macro_rules! concat_idents { + ($($e:ident),*) => ({ /* compiler built-in */ }) + } + + /// Concatenates literals into a static string slice. + /// + /// This macro takes any number of comma-separated literals, yielding an + /// expression of type `&'static str` which represents all of the literals + /// concatenated left-to-right. + /// + /// Integer and floating point literals are stringified in order to be + /// concatenated. + /// + /// # Example + /// + /// ``` + /// let s = concat!("test", 10i, 'b', true); + /// assert_eq!(s, "test10btrue"); + /// ``` + #[macro_export] + macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) } + + /// A macro which expands to the line number on which it was invoked. + /// + /// The expanded expression has type `uint`, and the returned line is not + /// the invocation of the `line!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `line!()` macro. + /// + /// # Example + /// + /// ``` + /// let current_line = line!(); + /// println!("defined on line: {}", current_line); + /// ``` + #[macro_export] + macro_rules! line { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the column number on which it was invoked. + /// + /// The expanded expression has type `uint`, and the returned column is not + /// the invocation of the `column!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `column!()` macro. + /// + /// # Example + /// + /// ``` + /// let current_col = column!(); + /// println!("defined on column: {}", current_col); + /// ``` + #[macro_export] + macro_rules! column { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the file name from which it was invoked. + /// + /// The expanded expression has type `&'static str`, and the returned file + /// is not the invocation of the `file!()` macro itself, but rather the + /// first macro invocation leading up to the invocation of the `file!()` + /// macro. + /// + /// # Example + /// + /// ``` + /// let this_file = file!(); + /// println!("defined in file: {}", this_file); + /// ``` + #[macro_export] + macro_rules! file { () => ({ /* compiler built-in */ }) } + + /// A macro which stringifies its argument. + /// + /// This macro will yield an expression of type `&'static str` which is the + /// stringification of all the tokens passed to the macro. No restrictions + /// are placed on the syntax of the macro invocation itself. + /// + /// # Example + /// + /// ``` + /// let one_plus_one = stringify!(1 + 1); + /// assert_eq!(one_plus_one, "1 + 1"); + /// ``` + #[macro_export] + macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) } + + /// Includes a utf8-encoded file as a string. + /// + /// This macro will yield an expression of type `&'static str` which is the + /// contents of the filename specified. The file is located relative to the + /// current file (similarly to how modules are found), + /// + /// # Example + /// + /// ```rust,ignore + /// let secret_key = include_str!("secret-key.ascii"); + /// ``` + #[macro_export] + macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + + /// Includes a file as a byte slice. + /// + /// This macro will yield an expression of type `&'static [u8]` which is + /// the contents of the filename specified. The file is located relative to + /// the current file (similarly to how modules are found), + /// + /// # Example + /// + /// ```rust,ignore + /// let secret_key = include_bytes!("secret-key.bin"); + /// ``` + #[macro_export] + macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + + /// Deprecated alias for `include_bytes!()`. + #[macro_export] + macro_rules! include_bin { ($file:expr) => ({ /* compiler built-in */}) } + + /// Expands to a string that represents the current module path. + /// + /// The current module path can be thought of as the hierarchy of modules + /// leading back up to the crate root. The first component of the path + /// returned is the name of the crate currently being compiled. + /// + /// # Example + /// + /// ```rust + /// mod test { + /// pub fn foo() { + /// assert!(module_path!().ends_with("test")); + /// } + /// } + /// + /// test::foo(); + /// ``` + #[macro_export] + macro_rules! module_path { () => ({ /* compiler built-in */ }) } + + /// Boolean evaluation of configuration flags. + /// + /// In addition to the `#[cfg]` attribute, this macro is provided to allow + /// boolean expression evaluation of configuration flags. This frequently + /// leads to less duplicated code. + /// + /// The syntax given to this macro is the same syntax as the `cfg` + /// attribute. + /// + /// # Example + /// + /// ```rust + /// let my_directory = if cfg!(windows) { + /// "windows-specific-directory" + /// } else { + /// "unix-directory" + /// }; + /// ``` + #[macro_export] + macro_rules! cfg { ($cfg:tt) => ({ /* compiler built-in */ }) } +} diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 6ae6a238c95..a79a6e35ebc 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -23,11 +23,14 @@ mod imp { use path::Path; use rand::Rng; use rand::reader::ReaderRng; - use result::Result::{Ok, Err}; + use result::Result::Ok; use slice::SliceExt; use mem; use os::errno; + // NOTE: for old macros; remove after the next snapshot + #[cfg(stage0)] use result::Result::Err; + #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index d48b0342b3b..ac1f0c5d803 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -17,8 +17,10 @@ use ops::{Add, Sub, Mul, Div, Neg, FnOnce}; use option::Option; use option::Option::{Some, None}; use num::Int; -use result::Result; -use result::Result::{Ok, Err}; +use result::Result::Ok; + +// NOTE: for old macros; remove after the next snapshot +#[cfg(stage0)] use result::Result::Err; /// The number of nanoseconds in a microsecond. const NANOS_PER_MICRO: i32 = 1000; diff --git a/src/test/run-pass/vec-macro-no-std.rs b/src/test/run-pass/vec-macro-no-std.rs new file mode 100644 index 00000000000..b01cad43603 --- /dev/null +++ b/src/test/run-pass/vec-macro-no-std.rs @@ -0,0 +1,39 @@ +// Copyright 2014 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. + +#![feature(phase, lang_items)] +#![no_std] + +#[phase(plugin, link)] +extern crate core; +extern crate libc; + +#[phase(plugin, link)] +extern crate collections; + +use core::option::Option::Some; +use core::slice::SliceExt; +use collections::vec::Vec; + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } + +// Issue #16806 + +#[start] +fn start(_argc: int, _argv: *const *const u8) -> int { + let x: Vec = vec![0, 1, 2]; + match x.last() { + Some(&2) => (), + _ => panic!(), + } + 0 +}