diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 00f2f37146db6..9fff5dd80eafd 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -761,6 +761,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Actually builds the expression which the format_args! block will be /// expanded to. fn into_expr(self) -> P { + let is_literal = self.str_pieces.len() == 1 && self.args.is_empty(); let mut locals = Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum()); let mut counts = Vec::with_capacity(self.count_args.len()); @@ -846,7 +847,9 @@ impl<'a, 'b> Context<'a, 'b> { let args_slice = self.ecx.expr_addr_of(self.macsp, result); // Now create the fmt::Arguments struct with all our locals we created. - let (fn_name, fn_args) = if self.all_pieces_simple { + let (fn_name, fn_args) = if is_literal { + ("new_literal", vec![pieces]) + } else if self.all_pieces_simple { ("new_v1", vec![pieces, args_slice]) } else { // Build up the static array which will store our precompiled diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 48142f66915bb..3e0f492d41e0e 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -332,6 +332,15 @@ enum FlagV1 { } impl<'a> Arguments<'a> { + /// When using the format_args!() macro, this function is used to generate the + /// Arguments structure in case it's just a single string literal. + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + pub const fn new_literal(pieces: &'a [&'static str; 1]) -> Arguments<'a> { + Arguments { pieces, fmt: None, args: &[] } + } + /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. #[doc(hidden)] diff --git a/src/test/pretty/dollar-crate.pp b/src/test/pretty/dollar-crate.pp index f4be3c1c63a84..d26352fccbaaa 100644 --- a/src/test/pretty/dollar-crate.pp +++ b/src/test/pretty/dollar-crate.pp @@ -9,10 +9,5 @@ // pp-exact:dollar-crate.pp fn main() { - { - ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], - &match () { - () => [], - })); - }; + { ::std::io::_print(::core::fmt::Arguments::new_literal(&["rust\n"])); }; } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 199aee05622be..444616a7d4456 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,29 +32,15 @@ ({ let res = ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_literal as - fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() - as - ()) - { - () - => - ([] - as - [ArgumentV1; 0]), - } - as - [ArgumentV1; 0]) - as - &[ArgumentV1; 0])) + fn(&[&'static str; 1]) -> Arguments {Arguments::new_literal})((&([("test" + as + &str)] + as + [&str; 1]) + as + &[&str; 1])) as Arguments)) as String); diff --git a/src/test/ui/consts/const-eval/format_args.rs b/src/test/ui/consts/const-eval/format_args.rs new file mode 100644 index 0000000000000..ed1c4002c9176 --- /dev/null +++ b/src/test/ui/consts/const-eval/format_args.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] + +const A: std::fmt::Arguments = format_args!("literal"); + +const B: std::fmt::Arguments = format_args!("{}", 123); +//~^ ERROR calls in constants are limited to +//~| ERROR calls in constants are limited to +//~| ERROR temporary value diff --git a/src/test/ui/consts/const-eval/format_args.stderr b/src/test/ui/consts/const-eval/format_args.stderr new file mode 100644 index 0000000000000..c82122ebaa4d2 --- /dev/null +++ b/src/test/ui/consts/const-eval/format_args.stderr @@ -0,0 +1,32 @@ +error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants + --> $DIR/format_args.rs:5:32 + | +LL | const B: std::fmt::Arguments = format_args!("{}", 123); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants + --> $DIR/format_args.rs:5:32 + | +LL | const B: std::fmt::Arguments = format_args!("{}", 123); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> $DIR/format_args.rs:5:32 + | +LL | const B: std::fmt::Arguments = format_args!("{}", 123); + | ^^^^^^^^^^^^^^^^^^^^^^- + | | | + | | temporary value is freed at the end of this statement + | creates a temporary which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + | + = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0015, E0716. +For more information about an error, try `rustc --explain E0015`.