diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 6c2659b13f720..9460b9a896646 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -945,6 +945,15 @@ pub trait ToString { } impl ToString for T { + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + fn to_string(&self) -> String { + let mut buf = Vec::::new(); + let _ = fmt::write(&mut buf, format_args!("{}", *self)); + String::from_utf8(buf).unwrap() + } + // NOTE(stage0): Remove method after a snapshot + #[cfg(stage0)] fn to_string(&self) -> String { let mut buf = Vec::::new(); let _ = format_args!(|args| fmt::write(&mut buf, args), "{}", self); diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 55a87973e0f5c..47701ab8ffd63 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -325,6 +325,13 @@ pub fn float_to_str_bytes_common( let mut filler = Filler { buf: &mut buf, end: &mut end }; match sign { + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + SignNeg => { + let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); + } + // NOTE(stage0): Remove match arm after a snapshot + #[cfg(stage0)] SignNeg => { let _ = format_args!(|args| { fmt::write(&mut filler, args) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index fb26450ec758e..b050b98de2f81 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -70,6 +70,16 @@ pub trait FormatWriter { /// This function will return an instance of `FormatError` on error. fn write(&mut self, bytes: &[u8]) -> Result; + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + /// Glue for usage of the `write!` macro with implementers of this trait. + /// + /// This method should generally not be invoked manually, but rather through + /// the `write!` macro itself. + fn write_fmt(&mut self, args: Arguments) -> Result { write(self, args) } + + // NOTE(stage0): Remove method after a snapshot + #[cfg(stage0)] /// Glue for usage of the `write!` macro with implementers of this trait. /// /// This method should generally not be invoked manually, but rather through @@ -180,6 +190,7 @@ impl<'a> Arguments<'a> { /// macro validates the format string at compile-time so usage of the `write` /// and `format` functions can be safely performed. #[stable] +#[deriving(Copy)] pub struct Arguments<'a> { // Format string pieces to print. pieces: &'a [&'a str], @@ -193,6 +204,14 @@ pub struct Arguments<'a> { } impl<'a> Show for Arguments<'a> { + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + fn fmt(&self, fmt: &mut Formatter) -> Result { + write(fmt.buf, *self) + } + + // NOTE(stage0): Remove method after a snapshot + #[cfg(stage0)] fn fmt(&self, fmt: &mut Formatter) -> Result { write(fmt.buf, self) } @@ -268,6 +287,63 @@ static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument { } }; +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// The `write` function takes an output stream, a precompiled format string, +/// and a list of arguments. The arguments will be formatted according to the +/// specified format string into the output stream provided. +/// +/// # Arguments +/// +/// * output - the buffer to write output to +/// * args - the precompiled arguments generated by `format_args!` +#[experimental = "libcore and I/O have yet to be reconciled, and this is an \ + implementation detail which should not otherwise be exported"] +pub fn write(output: &mut FormatWriter, args: Arguments) -> Result { + let mut formatter = Formatter { + flags: 0, + width: None, + precision: None, + buf: output, + align: rt::AlignUnknown, + fill: ' ', + args: args.args, + curarg: args.args.iter(), + }; + + let mut pieces = args.pieces.iter(); + + match args.fmt { + None => { + // We can use default formatting parameters for all arguments. + for _ in range(0, args.args.len()) { + try!(formatter.buf.write(pieces.next().unwrap().as_bytes())); + try!(formatter.run(&DEFAULT_ARGUMENT)); + } + } + Some(fmt) => { + // Every spec has a corresponding argument that is preceded by + // a string piece. + for (arg, piece) in fmt.iter().zip(pieces.by_ref()) { + try!(formatter.buf.write(piece.as_bytes())); + try!(formatter.run(arg)); + } + } + } + + // There can be only one trailing string piece left. + match pieces.next() { + Some(piece) => { + try!(formatter.buf.write(piece.as_bytes())); + } + None => {} + } + + Ok(()) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] /// The `write` function takes an output stream, a precompiled format string, /// and a list of arguments. The arguments will be formatted according to the /// specified format string into the output stream provided. @@ -527,6 +603,16 @@ impl<'a> Formatter<'a> { self.buf.write(data) } + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + /// Writes some formatted information into this instance + #[unstable = "reconciling core and I/O may alter this definition"] + pub fn write_fmt(&mut self, fmt: Arguments) -> Result { + write(self.buf, fmt) + } + + // NOTE(stage0): Remove method after a snapshot + #[cfg(stage0)] /// Writes some formatted information into this instance #[unstable = "reconciling core and I/O may alter this definition"] pub fn write_fmt(&mut self, fmt: &Arguments) -> Result { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9de723f38ee97..6d0d6e0817abd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -39,7 +39,7 @@ //! distribution. //! //! * `rust_begin_unwind` - This function takes three arguments, a -//! `&fmt::Arguments`, a `&str`, and a `uint`. These three arguments dictate +//! `fmt::Arguments`, a `&str`, and a `uint`. These three arguments dictate //! the panic message, the file at which panic was invoked, and the line. //! It is up to consumers of this core library to define this panic //! function; it is only required to never return. diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 7ce1da7d2d0f2..2cd9e7c45098e 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -10,6 +10,30 @@ #![macro_escape] +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// Entry point of task panic, for details, see std::macros +#[macro_export] +macro_rules! panic { + () => ( + panic!("explicit panic") + ); + ($msg:expr) => ({ + static _MSG_FILE_LINE: (&'static str, &'static str, uint) = ($msg, file!(), line!()); + ::core::panicking::panic(&_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!()); + ::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE) + }); +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Entry point of task panic, for details, see std::macros #[macro_export] macro_rules! panic { @@ -105,6 +129,16 @@ macro_rules! try { ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) }) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// Writing a formatted string into a writer +#[macro_export] +macro_rules! write { + ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Writing a formatted string into a writer #[macro_export] macro_rules! write { diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index fd0526db411cb..32f09a4c17f3c 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -16,7 +16,7 @@ //! interface for panicking is: //! //! ```ignore -//! fn panic_impl(fmt: &fmt::Arguments, &(&'static str, uint)) -> !; +//! fn panic_impl(fmt: fmt::Arguments, &(&'static str, uint)) -> !; //! ``` //! //! This definition allows for panicking with any general message, but it does not @@ -31,8 +31,20 @@ #![allow(dead_code, missing_docs)] use fmt; -use intrinsics; +// NOTE(stage0): Remove import after a snapshot +#[cfg(stage0)] use intrinsics; +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +#[cold] #[inline(never)] // this is the slow path, always +#[lang="panic"] +pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! { + let (expr, file, line) = *expr_file_line; + panic_fmt(format_args!("{}", expr), &(file, line)) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] #[cold] #[inline(never)] // this is the slow path, always #[lang="panic"] pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! { @@ -45,6 +57,18 @@ pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! { unsafe { intrinsics::abort() } } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +#[cold] #[inline(never)] +#[lang="panic_bounds_check"] +fn panic_bounds_check(file_line: &(&'static str, uint), + index: uint, len: uint) -> ! { + panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", + len, index), file_line) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] #[cold] #[inline(never)] #[lang="panic_bounds_check"] fn panic_bounds_check(file_line: &(&'static str, uint), @@ -55,6 +79,21 @@ fn panic_bounds_check(file_line: &(&'static str, uint), unsafe { intrinsics::abort() } } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +#[cold] #[inline(never)] +pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, uint)) -> ! { + #[allow(improper_ctypes)] + extern { + #[lang = "panic_fmt"] + fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: uint) -> !; + } + let (file, line) = *file_line; + unsafe { panic_impl(fmt, file, line) } +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] #[cold] #[inline(never)] pub fn panic_fmt(fmt: &fmt::Arguments, file_line: &(&'static str, uint)) -> ! { #[allow(improper_ctypes)] diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 97301628a4512..1d865868f1883 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -268,6 +268,8 @@ impl Drop for DefaultLogger { } } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] /// This function is called directly by the compiler when using the logging /// macros. This function does not take into account whether the log level /// specified is active or not, it will always log something if this method is @@ -276,7 +278,7 @@ impl Drop for DefaultLogger { /// It is not recommended to call this function directly, rather it should be /// invoked through the logging family of macros. #[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { +pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Test the literal string from args against the current filter, if there // is one. match unsafe { FILTER.as_ref() } { @@ -302,6 +304,42 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { set_logger(logger); } +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] +/// This function is called directly by the compiler when using the logging +/// macros. This function does not take into account whether the log level +/// specified is active or not, it will always log something if this method is +/// called. +/// +/// It is not recommended to call this function directly, rather it should be +/// invoked through the logging family of macros. +#[doc(hidden)] +pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { + // Test the literal string from args against the current filter, if there + // is one. + match unsafe { FILTER.as_ref() } { + Some(filter) if !filter.is_match(args.to_string().as_slice()) => return, + _ => {} + } + + // Completely remove the local logger from TLS in case anyone attempts to + // frob the slot while we're doing the logging. This will destroy any logger + // set during logging. + let mut logger = LOCAL_LOGGER.with(|s| { + s.borrow_mut().take() + }).unwrap_or_else(|| { + box DefaultLogger { handle: io::stderr() } as Box + }); + logger.log(&LogRecord { + level: LogLevel(level), + args: *args, + file: loc.file, + module_path: loc.module_path, + line: loc.line, + }); + set_logger(logger); +} + /// Getter for the global log level. This is a function so that it can be called /// safely #[doc(hidden)] @@ -329,7 +367,7 @@ pub struct LogRecord<'a> { pub level: LogLevel, /// The arguments from the log line. - pub args: &'a fmt::Arguments<'a>, + pub args: fmt::Arguments<'a>, /// The file of where the LogRecord originated. pub file: &'a str, diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs index 8b2cfcd420ac1..2e8302cc10f9a 100644 --- a/src/liblog/macros.rs +++ b/src/liblog/macros.rs @@ -12,6 +12,63 @@ #![macro_escape] +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// The standard logging macro +/// +/// This macro will generically log over a provided level (of type u32) with a +/// format!-based argument list. See documentation in `std::fmt` for details on +/// how to use the syntax. +/// +/// # Example +/// +/// ``` +/// #![feature(phase)] +/// #[phase(plugin, link)] extern crate log; +/// +/// fn main() { +/// log!(log::WARN, "this is a warning {}", "message"); +/// log!(log::DEBUG, "this is a debug message"); +/// log!(6, "this is a custom logging level: {level}", level=6u); +/// } +/// ``` +/// +/// Assumes the binary is `main`: +/// +/// ```{.bash} +/// $ RUST_LOG=warn ./main +/// WARN:main: this is a warning message +/// ``` +/// +/// ```{.bash} +/// $ RUST_LOG=debug ./main +/// DEBUG:main: this is a debug message +/// WARN:main: this is a warning message +/// ``` +/// +/// ```{.bash} +/// $ RUST_LOG=6 ./main +/// DEBUG:main: this is a debug message +/// WARN:main: this is a warning message +/// 6:main: this is a custom logging level: 6 +/// ``` +#[macro_export] +macro_rules! log { + ($lvl:expr, $($arg:tt)+) => ({ + static LOC: ::log::LogLocation = ::log::LogLocation { + line: line!(), + file: file!(), + module_path: module_path!(), + }; + let lvl = $lvl; + if log_enabled!(lvl) { + ::log::log(lvl, &LOC, format_args!($($arg)+)) + } + }) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// The standard logging macro /// /// This macro will generically log over a provided level (of type u32) with a diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index d0c9df9d914e7..b75cf9a196b50 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -16,13 +16,6 @@ //! This macro is implemented in the compiler to emit calls to this module in //! order to format arguments at runtime into strings and streams. //! -//! The functions contained in this module should not normally be used in -//! everyday use cases of `format!`. The assumptions made by these functions are -//! unsafe for all inputs, and the compiler performs a large amount of -//! validation on the arguments to `format!` in order to ensure safety at -//! runtime. While it is possible to call these functions directly, it is not -//! recommended to do so in the general case. -//! //! ## Usage //! //! The `format!` macro is intended to be familiar to those coming from C's @@ -275,35 +268,28 @@ //! //! # #[allow(unused_must_use)] //! # fn main() { -//! format_args!(fmt::format, "this returns {}", "String"); +//! fmt::format(format_args!("this returns {}", "String")); //! //! let some_writer: &mut io::Writer = &mut io::stdout(); -//! format_args!(|args| { write!(some_writer, "{}", args) }, -//! "print with a {}", "closure"); +//! write!(some_writer, "{}", format_args!("print with a {}", "macro")); //! -//! fn my_fmt_fn(args: &fmt::Arguments) { +//! fn my_fmt_fn(args: fmt::Arguments) { //! write!(&mut io::stdout(), "{}", args); //! } -//! format_args!(my_fmt_fn, "or a {} too", "function"); +//! my_fmt_fn(format_args!("or a {} too", "function")); //! # } //! ``` //! -//! The first argument of the `format_args!` macro is a function (or closure) -//! which takes one argument of type `&fmt::Arguments`. This structure can then -//! be passed to the `write` and `format` functions inside this module in order -//! to process the format string. The goal of this macro is to even further -//! prevent intermediate allocations when dealing formatting strings. +//! The result of the `format_args!` macro is a value of type `fmt::Arguments`. +//! This structure can then be passed to the `write` and `format` functions +//! inside this module in order to process the format string. +//! The goal of this macro is to even further prevent intermediate allocations +//! when dealing formatting strings. //! //! For example, a logging library could use the standard formatting syntax, but //! it would internally pass around this structure until it has been determined //! where output should go to. //! -//! It is unsafe to programmatically create an instance of `fmt::Arguments` -//! because the operations performed when executing a format string require the -//! compile-time checks provided by the compiler. The `format_args!` macro is -//! the only method of safely creating these structures, but they can be -//! unsafely created with the constructor provided. -//! //! ## Syntax //! //! The syntax for the formatting language used is drawn from other languages, @@ -420,14 +406,39 @@ pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt}; #[doc(hidden)] pub use core::fmt::{argument, argumentuint}; +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// The format function takes a precompiled format string and a list of +/// arguments, to return the resulting formatted string. +/// +/// # Arguments +/// +/// * args - a structure of arguments generated via the `format_args!` macro. +/// +/// # Example +/// +/// ```rust +/// use std::fmt; +/// +/// let s = fmt::format(format_args!("Hello, {}!", "world")); +/// assert_eq!(s, "Hello, world!".to_string()); +/// ``` +#[experimental = "this is an implementation detail of format! and should not \ + be called directly"] +pub fn format(args: Arguments) -> string::String { + let mut output = Vec::new(); + let _ = write!(&mut output as &mut Writer, "{}", args); + string::String::from_utf8(output).unwrap() +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] /// The format function takes a precompiled format string and a list of /// arguments, to return the resulting formatted string. /// /// # Arguments /// /// * args - a structure of arguments generated via the `format_args!` macro. -/// Because this structure can only be safely generated at -/// compile-time, this function is safe. /// /// # Example /// diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 233ad78109382..b6f8bb25b6531 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1017,6 +1017,48 @@ pub trait Writer { /// decide whether their stream needs to be buffered or not. fn flush(&mut self) -> IoResult<()> { Ok(()) } + // NOTE(stage0): Remove cfg after a snapshot + #[cfg(not(stage0))] + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the `format_args!` + /// macro, but it is rare that this should explicitly be called. The + /// `write!` macro should be favored to invoke this method instead. + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { + // Create a shim which translates a Writer to a FormatWriter and saves + // off I/O errors. instead of discarding them + struct Adaptor<'a, T:'a> { + inner: &'a mut T, + error: IoResult<()>, + } + + impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> { + fn write(&mut self, bytes: &[u8]) -> fmt::Result { + match self.inner.write(bytes) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adaptor { inner: self, error: Ok(()) }; + match fmt::write(&mut output, fmt) { + Ok(()) => Ok(()), + Err(..) => output.error + } + } + + + // NOTE(stage0): Remove method after a snapshot + #[cfg(stage0)] /// Writes a formatted string into this writer, returning any error /// encountered. /// diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index b7da57fed2708..6bd721599f341 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -378,12 +378,32 @@ pub fn println(s: &str) { }) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible +/// with the `format_args!` macro. +pub fn print_args(fmt: fmt::Arguments) { + with_task_stdout(|io| write!(io, "{}", fmt)) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] /// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible /// with the `format_args!` macro. pub fn print_args(fmt: &fmt::Arguments) { with_task_stdout(|io| write!(io, "{}", fmt)) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// Similar to `println`, but takes a `fmt::Arguments` structure to be +/// compatible with the `format_args!` macro. +pub fn println_args(fmt: fmt::Arguments) { + with_task_stdout(|io| writeln!(io, "{}", fmt)) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] /// Similar to `println`, but takes a `fmt::Arguments` structure to be /// compatible with the `format_args!` macro. pub fn println_args(fmt: &fmt::Arguments) { diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index d90a47ea4ea8c..edb6218c5cc0b 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -17,6 +17,50 @@ #![experimental] #![macro_escape] +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// 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) + + }); +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// The entry point for panic of Rust tasks. /// /// This macro is used to inject panic into a Rust task, causing the task to @@ -245,6 +289,26 @@ macro_rules! unimplemented { () => (panic!("not yet implemented")) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// 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)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Use the syntax described in `std::fmt` to create a value of type `String`. /// See `std::fmt` for more information. /// @@ -263,6 +327,28 @@ macro_rules! format { ) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// 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)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. /// See `std::fmt` for more information. /// @@ -294,6 +380,18 @@ macro_rules! writeln { ) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// 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)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Equivalent to the `println!` macro except that a newline is not printed at /// the end of the message. #[macro_export] @@ -302,6 +400,28 @@ macro_rules! print { ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// 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)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] /// Macro for printing to a task's stdout handle. /// /// Each task can override its stdout handle via `std::io::stdio::set_stdout`. @@ -411,11 +531,10 @@ macro_rules! log { pub mod builtin { /// The core macro for formatted string creation & output. /// - /// This macro takes as its first argument a callable expression which will - /// receive as its first argument 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. + /// 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`. /// @@ -424,15 +543,12 @@ pub mod builtin { /// ```rust /// use std::fmt; /// - /// let s = format_args!(fmt::format, "hello {}", "world"); + /// let s = fmt::format(format_args!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world")); /// - /// format_args!(|args| { - /// // pass `args` to another function, etc. - /// }, "hello {}", "world"); /// ``` #[macro_export] - macro_rules! format_args { ($closure:expr, $fmt:expr $($args:tt)*) => ({ + macro_rules! format_args { ($fmt:expr $($args:tt)*) => ({ /* compiler built-in */ }) } diff --git a/src/libstd/rt/macros.rs b/src/libstd/rt/macros.rs index bee8b5b82f48e..095a27203f981 100644 --- a/src/libstd/rt/macros.rs +++ b/src/libstd/rt/macros.rs @@ -15,6 +15,16 @@ #![macro_escape] +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +macro_rules! rterrln { + ($fmt:expr $($arg:tt)*) => ( { + ::rt::util::dumb_print(format_args!(concat!($fmt, "\n") $($arg)*)) + } ) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! rterrln { ($fmt:expr $($arg:tt)*) => ( { format_args!(::rt::util::dumb_print, concat!($fmt, "\n") $($arg)*) @@ -40,6 +50,14 @@ macro_rules! rtassert { } ) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +macro_rules! rtabort { + ($($arg:tt)*) => (::rt::util::abort(format_args!($($arg)*))) +} + +// NOTE(stage0): Remove macro after a snapshot +#[cfg(stage0)] macro_rules! rtabort { ($($arg:tt)*) => (format_args!(::rt::util::abort, $($arg)*)) } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index eb15a7ba378e0..261a8335173d0 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -477,14 +477,61 @@ pub mod eabi { } } -// Entry point of panic from the libcore crate +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] #[cfg(not(test))] +/// Entry point of panic from the libcore crate. +#[lang = "panic_fmt"] +pub extern fn rust_begin_unwind(msg: fmt::Arguments, + file: &'static str, line: uint) -> ! { + begin_unwind_fmt(msg, &(file, line)) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] +#[cfg(not(test))] +/// Entry point of panic from the libcore crate. #[lang = "panic_fmt"] pub extern fn rust_begin_unwind(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! { begin_unwind_fmt(msg, &(file, line)) } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +/// The entry point for unwinding with a formatted message. +/// +/// This is designed to reduce the amount of code required at the call +/// site as much as possible (so that `panic!()` has as low an impact +/// on (e.g.) the inlining of other functions as possible), by moving +/// the actual formatting into this shared place. +#[inline(never)] #[cold] +pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! { + use fmt::FormatWriter; + + // We do two allocations here, unfortunately. But (a) they're + // required with the current scheme, and (b) we don't handle + // panic + OOM properly anyway (see comment in begin_unwind + // below). + + struct VecWriter<'a> { v: &'a mut Vec } + + impl<'a> fmt::FormatWriter for VecWriter<'a> { + fn write(&mut self, buf: &[u8]) -> fmt::Result { + self.v.push_all(buf); + Ok(()) + } + } + + let mut v = Vec::new(); + let _ = write!(&mut VecWriter { v: &mut v }, "{}", msg); + + let msg = box String::from_utf8_lossy(v.as_slice()).into_owned(); + begin_unwind_inner(msg, file_line) +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] /// The entry point for unwinding with a formatted message. /// /// This is designed to reduce the amount of code required at the call diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index d8cd8455deb5c..26dadfd9fb1db 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -112,12 +112,25 @@ impl fmt::FormatWriter for Stdio { } } +// NOTE(stage0): Remove cfg after a snapshot +#[cfg(not(stage0))] +pub fn dumb_print(args: fmt::Arguments) { + let _ = Stderr.write_fmt(args); +} + +// NOTE(stage0): Remove function after a snapshot +#[cfg(stage0)] pub fn dumb_print(args: &fmt::Arguments) { let mut w = Stderr; let _ = write!(&mut w, "{}", args); } -pub fn abort(args: &fmt::Arguments) -> ! { +// NOTE(stage0): Remove wrappers after a snapshot +#[cfg(not(stage0))] pub fn abort(args: fmt::Arguments) -> ! { abort_(&args) } +#[cfg(stage0)] pub fn abort(args: &fmt::Arguments) -> ! { abort_(args) } + +// NOTE(stage0): Change to `pub fn abort(args: fmt::Arguments) -> !` after a snapshot +fn abort_(args: &fmt::Arguments) -> ! { use fmt::FormatWriter; struct BufWriter<'a> { diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index 19b45a1e61007..2788c89676a3a 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -131,8 +131,10 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, let format_string = cx.expr_str(span, s); // phew, not our responsibility any more! - format::expand_preparsed_format_args(cx, span, - format::MethodCall(formatter, meth), - format_string, exprs, Vec::new(), - HashMap::new()) + + let args = vec![ + format::expand_preparsed_format_args(cx, span, format_string, + exprs, vec![], HashMap::new()) + ]; + cx.expr_method_call(span, formatter, meth, args) } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index aad4045f00a52..6474d92953fd1 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::Invocation::*; use self::ArgumentType::*; use self::Position::*; @@ -23,17 +22,16 @@ use parse::token; use ptr::P; use std::collections::HashMap; -use std::string; #[deriving(PartialEq)] enum ArgumentType { - Known(string::String), + Known(String), Unsigned } enum Position { Exact(uint), - Named(string::String), + Named(String), } struct Context<'a, 'b:'a> { @@ -48,12 +46,12 @@ struct Context<'a, 'b:'a> { /// Note that we keep a side-array of the ordering of the named arguments /// found to be sure that we can translate them in the same order that they /// were declared in. - names: HashMap>, - name_types: HashMap, - name_ordering: Vec, + names: HashMap>, + name_types: HashMap, + name_ordering: Vec, /// The latest consecutive literal strings, or empty if there weren't any. - literal: string::String, + literal: String, /// Collection of the compiled `rt::Argument` structures pieces: Vec>, @@ -62,62 +60,40 @@ struct Context<'a, 'b:'a> { /// Stays `true` if all formatting parameters are default (as in "{}{}"). all_pieces_simple: bool, - name_positions: HashMap, - method_statics: Vec>, + name_positions: HashMap, /// Updated as arguments are consumed or methods are entered nest_level: uint, next_arg: uint, } -pub enum Invocation { - Call(P), - MethodCall(P, ast::Ident), -} - /// Parses the arguments from the given list of tokens, returning None /// if there's a parse error so we can continue parsing other format! /// expressions. /// -/// If parsing succeeds, the second return value is: +/// If parsing succeeds, the return value is: /// /// Some((fmtstr, unnamed arguments, ordering of named arguments, /// named arguments)) -fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool, - tts: &[ast::TokenTree]) - -> (Invocation, Option<(P, Vec>, Vec, - HashMap>)>) { +fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Option<(P, Vec>, Vec, + HashMap>)> { let mut args = Vec::new(); - let mut names = HashMap::>::new(); + let mut names = HashMap::>::new(); let mut order = Vec::new(); let mut p = ecx.new_parser_from_tts(tts); - // Parse the leading function expression (maybe a block, maybe a path) - let invocation = if allow_method { - let e = p.parse_expr(); - if !p.eat(&token::Comma) { - ecx.span_err(sp, "expected token: `,`"); - return (Call(e), None); - } - MethodCall(e, p.parse_ident()) - } else { - Call(p.parse_expr()) - }; - if !p.eat(&token::Comma) { - ecx.span_err(sp, "expected token: `,`"); - return (invocation, None); - } if p.token == token::Eof { ecx.span_err(sp, "requires at least a format string argument"); - return (invocation, None); + return None; } let fmtstr = p.parse_expr(); let mut named = false; while p.token != token::Eof { if !p.eat(&token::Comma) { ecx.span_err(sp, "expected token: `,`"); - return (invocation, None); + return None; } if p.token == token::Eof { break } // accept trailing commas if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) { @@ -131,13 +107,13 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool, ecx.span_err(p.span, "expected ident, positional arguments \ cannot follow named arguments"); - return (invocation, None); + return None; } _ => { ecx.span_err(p.span, format!("expected ident for named argument, found `{}`", p.this_token_to_string())[]); - return (invocation, None); + return None; } }; let interned_name = token::get_ident(ident); @@ -160,7 +136,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool, args.push(p.parse_expr()); } } - return (invocation, Some((fmtstr, args, order, names))); + Some((fmtstr, args, order, names)) } impl<'a, 'b> Context<'a, 'b> { @@ -225,7 +201,7 @@ impl<'a, 'b> Context<'a, 'b> { } } - fn describe_num_args(&self) -> string::String { + fn describe_num_args(&self) -> String { match self.args.len() { 0 => "no arguments given".to_string(), 1 => "there is 1 argument".to_string(), @@ -474,70 +450,50 @@ impl<'a, 'b> Context<'a, 'b> { } } - fn item_static_array(ecx: &mut ExtCtxt, - name: ast::Ident, - piece_ty: P, - pieces: Vec>) - -> P { + fn static_array(ecx: &mut ExtCtxt, + name: &str, + piece_ty: P, + pieces: Vec>) + -> P { let fmtsp = piece_ty.span; - let fmt = ecx.expr_vec(fmtsp, pieces); - let fmt = ecx.expr_addr_of(fmtsp, fmt); - let ty = ast::TyVec(piece_ty); - let ty = ast::TyRptr(Some(ecx.lifetime(fmtsp, special_idents::static_lifetime.name)), - ast::MutTy{ mutbl: ast::MutImmutable, ty: ecx.ty(fmtsp, ty) }); - let ty = ecx.ty(fmtsp, ty); - let st = ast::ItemStatic(ty, ast::MutImmutable, fmt); + let ty = ecx.ty_rptr(fmtsp, + ecx.ty(fmtsp, ast::TyVec(piece_ty)), + Some(ecx.lifetime(fmtsp, special_idents::static_lifetime.name)), + ast::MutImmutable); + let slice = ecx.expr_vec_slice(fmtsp, pieces); + let st = ast::ItemStatic(ty, ast::MutImmutable, slice); + + let name = ecx.ident_of(name); let item = ecx.item(fmtsp, name, Context::static_attrs(ecx, fmtsp), st); let decl = respan(fmtsp, ast::DeclItem(item)); - P(respan(fmtsp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))) + + // Wrap the declaration in a block so that it forms a single expression. + ecx.expr_block(ecx.block(fmtsp, + vec![P(respan(fmtsp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], + Some(ecx.expr_ident(fmtsp, name)))) } /// Actually builds the expression which the iformat! block will be expanded /// to - fn to_expr(mut self, invocation: Invocation) -> P { - let mut lets = Vec::new(); + fn into_expr(mut self) -> P { let mut locals = Vec::new(); let mut names = Vec::from_fn(self.name_positions.len(), |_| None); let mut pats = Vec::new(); let mut heads = Vec::new(); - // First, declare all of our methods that are statics - for method in self.method_statics.into_iter() { - let decl = respan(self.fmtsp, ast::DeclItem(method)); - lets.push(P(respan(self.fmtsp, - ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))); - } - - // Next, build up the static array which will become our precompiled + // First, build up the static array which will become our precompiled // format "string" - let static_str_name = self.ecx.ident_of("__STATIC_FMTSTR"); - let static_lifetime = self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("'static").name); + let static_lifetime = self.ecx.lifetime(self.fmtsp, special_idents::static_lifetime.name); let piece_ty = self.ecx.ty_rptr( self.fmtsp, self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")), Some(static_lifetime), ast::MutImmutable); - lets.push(Context::item_static_array(self.ecx, - static_str_name, - piece_ty, - self.str_pieces)); - - // Then, build up the static array which will store our precompiled - // nonstandard placeholders, if there are any. - let static_args_name = self.ecx.ident_of("__STATIC_FMTARGS"); - if !self.all_pieces_simple { - let piece_ty = self.ecx.ty_path(self.ecx.path_all( - self.fmtsp, - true, Context::rtpath(self.ecx, "Argument"), - vec![static_lifetime], - vec![], - vec![] - )); - lets.push(Context::item_static_array(self.ecx, - static_args_name, - piece_ty, - self.pieces)); - } + let pieces = Context::static_array(self.ecx, + "__STATIC_FMTSTR", + piece_ty, + self.str_pieces); + // Right now there is a bug such that for the expression: // foo(bar(&1)) @@ -580,71 +536,68 @@ impl<'a, 'b> Context<'a, 'b> { // Now create a vector containing all the arguments let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap())); - // Now create the fmt::Arguments struct with all our locals we created. - let pieces = self.ecx.expr_ident(self.fmtsp, static_str_name); - let args_slice = self.ecx.expr_vec_slice(self.fmtsp, args.collect()); - - let (fn_name, fn_args) = if self.all_pieces_simple { - ("new", vec![pieces, args_slice]) - } else { - let fmt = self.ecx.expr_ident(self.fmtsp, static_args_name); - ("with_placeholders", vec![pieces, fmt, args_slice]) - }; - - let result = self.ecx.expr_call_global(self.fmtsp, vec!( - self.ecx.ident_of("std"), - self.ecx.ident_of("fmt"), - self.ecx.ident_of("Arguments"), - self.ecx.ident_of(fn_name)), fn_args); - - let result = match invocation { - Call(e) => { - let span = e.span; - self.ecx.expr_call(span, e, vec![ - self.ecx.expr_addr_of(span, result) - ]) - } - MethodCall(e, m) => { - let span = e.span; - self.ecx.expr_method_call(span, e, m, vec![ - self.ecx.expr_addr_of(span, result) - ]) - } - }; - let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, - Some(result))); + let args_array = self.ecx.expr_vec(self.fmtsp, args.collect()); // Constructs an AST equivalent to: // // match (&arg0, &arg1) { - // (tmp0, tmp1) => body + // (tmp0, tmp1) => args_array // } // // It was: // // let tmp0 = &arg0; // let tmp1 = &arg1; - // body + // args_array // // Because of #11585 the new temporary lifetime rule, the enclosing // statements for these temporaries become the let's themselves. // If one or more of them are RefCell's, RefCell borrow() will also - // end there; they don't last long enough for body to use them. The - // match expression solves the scope problem. + // end there; they don't last long enough for args_array to use them. + // The match expression solves the scope problem. // // Note, it may also very well be transformed to: // // match arg0 { // ref tmp0 => { // match arg1 => { - // ref tmp1 => body } } } + // ref tmp1 => args_array } } } // // But the nested match expression is proved to perform not as well // as series of let's; the first approach does. let pat = self.ecx.pat_tuple(self.fmtsp, pats); - let arm = self.ecx.arm(self.fmtsp, vec!(pat), body); + let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array); let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads)); - self.ecx.expr_match(self.fmtsp, head, vec!(arm)) + let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm)); + + let args_slice = self.ecx.expr_addr_of(self.fmtsp, result); + + // Now create the fmt::Arguments struct with all our locals we created. + let (fn_name, fn_args) = if self.all_pieces_simple { + ("new", vec![pieces, args_slice]) + } else { + // Build up the static array which will store our precompiled + // nonstandard placeholders, if there are any. + let piece_ty = self.ecx.ty_path(self.ecx.path_all( + self.fmtsp, + true, Context::rtpath(self.ecx, "Argument"), + vec![static_lifetime], + vec![], + vec![] + )); + let fmt = Context::static_array(self.ecx, + "__STATIC_FMTARGS", + piece_ty, + self.pieces); + + ("with_placeholders", vec![pieces, fmt, args_slice]) + }; + + self.ecx.expr_call_global(self.fmtsp, vec!( + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("Arguments"), + self.ecx.ident_of(fn_name)), fn_args) } fn format_arg(ecx: &ExtCtxt, sp: Span, @@ -694,24 +647,22 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - match parse_args(ecx, sp, false, tts) { - (invocation, Some((efmt, args, order, names))) => { - MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt, + match parse_args(ecx, sp, tts) { + Some((efmt, args, order, names)) => { + MacExpr::new(expand_preparsed_format_args(ecx, sp, efmt, args, order, names)) } - (_, None) => MacExpr::new(ecx.expr_uint(sp, 2)) + None => DummyResult::expr(sp) } } -/// Take the various parts of `format_args!(extra, efmt, args..., -/// name=names...)` and construct the appropriate formatting -/// expression. +/// Take the various parts of `format_args!(efmt, args..., name=names...)` +/// and construct the appropriate formatting expression. pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, - invocation: Invocation, efmt: P, args: Vec>, - name_ordering: Vec, - names: HashMap>) + name_ordering: Vec, + names: HashMap>) -> P { let arg_types = Vec::from_fn(args.len(), |_| None); let mut cx = Context { @@ -724,17 +675,16 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, name_ordering: name_ordering, nest_level: 0, next_arg: 0, - literal: string::String::new(), + literal: String::new(), pieces: Vec::new(), str_pieces: Vec::new(), all_pieces_simple: true, - method_statics: Vec::new(), fmtsp: sp, }; cx.fmtsp = efmt.span; let fmt = match expr_to_string(cx.ecx, - efmt, - "format argument must be a string literal.") { + efmt, + "format argument must be a string literal.") { Some((fmt, _)) => fmt, None => return DummyResult::raw_expr(sp) }; @@ -782,5 +732,5 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, } } - cx.to_expr(invocation) + cx.into_expr() } diff --git a/src/test/compile-fail/dead-code-closure-bang.rs b/src/test/compile-fail/dead-code-closure-bang.rs index 3179b1815609f..0aa3c40fa5f88 100644 --- a/src/test/compile-fail/dead-code-closure-bang.rs +++ b/src/test/compile-fail/dead-code-closure-bang.rs @@ -13,5 +13,5 @@ fn main() { let x: || -> ! = || panic!(); x(); - println!("Foo bar"); //~ ERROR: unreachable statement + std::io::println("Foo bar"); //~ ERROR: unreachable statement } diff --git a/src/test/compile-fail/ifmt-bad-format-args.rs b/src/test/compile-fail/ifmt-bad-format-args.rs index d2a3fe2a9b1c2..8bd3cb0f60b04 100644 --- a/src/test/compile-fail/ifmt-bad-format-args.rs +++ b/src/test/compile-fail/ifmt-bad-format-args.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - format_args!("test"); //~ ERROR: expected token - format_args!("", || {}); //~ ERROR: must be a string literal + format_args!(); //~ ERROR: requires at least a format string argument + format_args!(|| {}); //~ ERROR: must be a string literal } diff --git a/src/test/compile-fail/ifmt-bad-format-args2.rs b/src/test/compile-fail/ifmt-bad-format-args2.rs deleted file mode 100644 index 7bb8365bc128e..0000000000000 --- a/src/test/compile-fail/ifmt-bad-format-args2.rs +++ /dev/null @@ -1,13 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - format_args!("{}", ""); //~ ERROR: expected function -} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index e4389cd69dd62..c2ebd764ad6b9 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -34,13 +34,6 @@ [int; 3]) as &[int; 3]) as *const _ as *const [int; 3]) as *const [int; (3u as uint)] as *const [int; 3]); - (match (() as ()) { - () => { - #[inline] - #[allow(dead_code)] - static __STATIC_FMTSTR: &'static [&'static str] = - (&([("test" as &'static str)] as [&'static str; 1]) as - &'static [&'static str; 1]); @@ -49,24 +42,45 @@ - ((::std::fmt::format as - fn(&core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})((&((::std::fmt::Arguments::new - as - fn(&[&str], &[core::fmt::Argument<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new})((__STATIC_FMTSTR - as - &'static [&'static str]), - (&([] - as - [core::fmt::Argument<'_>; 0]) - as - &[core::fmt::Argument<'_>; 0])) - as - core::fmt::Arguments<'_>) - as - &core::fmt::Arguments<'_>)) - as collections::string::String) - } - } as collections::string::String); + ((::std::fmt::format as + fn(core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})(((::std::fmt::Arguments::new + as + fn(&[&str], &[core::fmt::Argument<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new})(({ + #[inline] + #[allow(dead_code)] + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" + as + &'static str)] + as + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [core::fmt::Argument<'_>; 0]), + } + as + [core::fmt::Argument<'_>; 0]) + as + &[core::fmt::Argument<'_>; 0])) + as + core::fmt::Arguments<'_>)) + as collections::string::String); } pub type Foo = [int; (3u as uint)]; pub struct Bar { diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index f3e15562b6dc9..fa62699a30378 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -190,18 +190,16 @@ fn test_format_args() { let mut buf = Vec::new(); { let w = &mut buf as &mut io::Writer; - format_args!(|args| { write!(w, "{}", args); }, "{}", 1i); - format_args!(|args| { write!(w, "{}", args); }, "test"); - format_args!(|args| { write!(w, "{}", args); }, "{test}", test=3i); + write!(w, "{}", format_args!("{}", 1i)); + write!(w, "{}", format_args!("test")); + write!(w, "{}", format_args!("{test}", test=3i)); } let s = String::from_utf8(buf).unwrap(); t!(s, "1test3"); - let s = format_args!(fmt::format, "hello {}", "world"); + let s = fmt::format(format_args!("hello {}", "world")); t!(s, "hello world"); - let s = format_args!(|args| { - format!("{}: {}", "args were", args) - }, "hello {}", "world"); + let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); t!(s, "args were: hello world"); }