diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index c694806b4bab9f60203f0c485da1160bf611399d..9b9af2c65cad5773fa2b98ed4a34f18865409a7c 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -440,14 +440,18 @@ to print "I am never printed" and to run forever. # Scoping and macro import/export -Macros occupy a single global namespace. The interaction with Rust's system of -modules and crates is somewhat complex. +Macros are expanded at an early stage in compilation, before name resolution. +One downside is that scoping works differently for macros, compared to other +constructs in the language. Definition and expansion of macros both happen in a single depth-first, lexical-order traversal of a crate's source. So a macro defined at module scope is visible to any subsequent code in the same module, which includes the body of any subsequent child `mod` items. +A macro defined within the body of a single `fn`, or anywhere else not at +module scope, is visible only within that item. + If a module has the `macro_use` attribute, its macros are also visible in its parent module after the child's `mod` item. If the parent also has `macro_use` then the macros will be visible in the grandparent after the parent's `mod` diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f6415518864bf934e80e8f62adcaa66b61af14a6..3d3b9f8cf658577389f7e89f9c28310460d0a2a7 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -49,15 +49,16 @@ /// assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[macro_export] +#[stable] macro_rules! assert { ($cond:expr) => ( if !$cond { panic!(concat!("assertion failed: ", stringify!($cond))) } ); - ($cond:expr, $($arg:expr),+) => ( + ($cond:expr, $($arg:tt)+) => ( if !$cond { - panic!($($arg),+) + panic!($($arg)+) } ); } @@ -75,6 +76,7 @@ /// assert_eq!(a, b); /// ``` #[macro_export] +#[stable] macro_rules! assert_eq { ($left:expr , $right:expr) => ({ match (&($left), &($right)) { @@ -116,6 +118,7 @@ /// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[macro_export] +#[stable] macro_rules! debug_assert { ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) } @@ -227,6 +230,7 @@ /// } /// ``` #[macro_export] +#[unstable = "relationship with panic is unclear"] macro_rules! unreachable { () => ({ panic!("internal error: entered unreachable code") @@ -242,6 +246,7 @@ /// A standardised placeholder for marking unfinished code. It panics with the /// message `"not yet implemented"` when executed. #[macro_export] +#[unstable = "relationship with panic is unclear"] macro_rules! unimplemented { () => (panic!("not yet implemented")) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index dc157c7d67660ef6d5a4a0888267cfe06f69db40..e15e611adc08cfc8aacc743886e77656773e1f83 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -122,7 +122,8 @@ extern crate log; #[macro_use] -#[macro_reexport(write, writeln)] +#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, + unreachable, unimplemented, write, writeln)] extern crate core; #[macro_use] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 626372db23b5f23a2b760441adc4f688f62ff3b4..a420c841d25e3196b9bbeb8ce82f324277271505 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -60,184 +60,6 @@ }); } -/// 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] -#[stable] -macro_rules! assert { - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr, $($arg:tt)+) => ( - 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] -#[stable] -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] -#[stable] -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] -#[unstable = "relationship with panic is unclear"] -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] -#[unstable = "relationship with panic is unclear"] -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. ///