From be1ea4bc7901a14e38602518bd9ec1177904e3cb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 21 Aug 2020 07:49:15 +0000 Subject: [PATCH] Use str::to_owned for `format!` without formatting arguments --- library/alloc/src/lib.rs | 1 + library/alloc/src/macros.rs | 16 ++++- .../issue-75742-format_without_fmt_args.rs | 39 ++++++++++ src/test/pretty/issue-4264.pp | 71 +++++++++++-------- src/test/ui/borrowck/issue-64453.rs | 2 + src/test/ui/borrowck/issue-64453.stderr | 20 +++++- 6 files changed, 116 insertions(+), 33 deletions(-) create mode 100644 src/test/codegen/issue-75742-format_without_fmt_args.rs diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b33cb3ad8e839..78ab5c7b809e5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -97,6 +97,7 @@ #![feature(exact_size_is_empty)] #![feature(exclusive_range_pattern)] #![feature(extend_one)] +#![feature(fmt_as_str)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 2f744618d6936..806234ea364c4 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -101,9 +101,21 @@ macro_rules! vec { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable(fmt_as_str)] macro_rules! format { ($($arg:tt)*) => {{ - let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); - res + // NOTE: `format_args!` borrows from temporaries. This means that + // `match` is necessary to extend the lifetime of the temporaries until after + // the `Arguments` is no longer used. The same pattern is used + // inside `format_args!` itself. + let r = match $crate::__export::format_args!($($arg)*) { + // HACK: We hope that constant propagation will make LLVM optimize out + // this match. + args => match args.as_str() { + Some(s) => $crate::borrow::ToOwned::to_owned(s), + None => $crate::fmt::format(args), + } + }; + r }} } diff --git a/src/test/codegen/issue-75742-format_without_fmt_args.rs b/src/test/codegen/issue-75742-format_without_fmt_args.rs new file mode 100644 index 0000000000000..3201688fb0301 --- /dev/null +++ b/src/test/codegen/issue-75742-format_without_fmt_args.rs @@ -0,0 +1,39 @@ +// min-llvm-version: 10.0.0 +// compile-flags: -C opt-level=3 +#![crate_type = "rlib"] +#![feature(format_args_capture)] + +// Make sure allocation not happen when result of `format!` is unused and +// there are no formatting arguments. + +// CHECK-LABEL: @format_wo_fmt_args +// CHECK-NEXT: {{"_ZN[^:]+"}}: +// CHECK-NEXT: ret +#[no_mangle] +pub fn format_wo_fmt_args() { + format!(""); + format!("a long story"); + format!("a long story {{"); +} + +// CHECK-LABEL: @format_wo_fmt_args_ret +// CHECK-NOT: Arguments +#[no_mangle] +pub fn format_wo_fmt_args_ret() -> String { + format!("a long story") +} + +// CHECK-LABEL: @format_w_fmt_args_ret_1 +// CHECK: alloc::fmt::format +#[no_mangle] +pub fn format_w_fmt_args_ret_1(n: usize) -> String { + format!("a long story: {}", n) +} + +// CHECK-LABEL: @format_w_fmt_args_ret_2 +// CHECK: core::fmt::ArgumentV1::from_usize +// CHECK: alloc::fmt::format +#[no_mangle] +pub fn format_w_fmt_args_ret_2(n: usize, width: usize) -> String { + format!("a long story {n:width$}") +} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 7b0a00282fbb0..dd708a3fdcf72 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -30,35 +30,48 @@ ({ - let res = - ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 - 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])) - as - Arguments)) - as String); - (res as String) + let r = + (match ((::core::fmt::Arguments::new_v1 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])) + as Arguments) { + args => + (match ((args as Arguments).as_str() as + Option<&str>) { + Some(s) => + ((::alloc::borrow::ToOwned::to_owned as + for<'r> fn(&'r str) -> ::Owned {::to_owned})((s + as + &str)) + as String), + None => + ((::alloc::fmt::format as + for<'r> fn(Arguments<'r>) -> String {format})((args + as + Arguments)) + as String), + } as String), + } as String); + (r as String) } as String); } as ()) pub type Foo = [i32; (3 as usize)]; diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 3e803f3b6d8b2..8ccb8f0050685 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -4,6 +4,8 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR calls in statics are limited to constant functions //~| ERROR calls in statics are limited to constant functions +//~| ERROR calls in statics are limited to constant functions +//~| ERROR calls in statics are limited to constant functions fn from_string(_: String) -> Value { Value diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index fba801983cf4e..38cbb7fc9585a 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:16:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait @@ -20,7 +20,23 @@ LL | static settings_dir: String = format!(""); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`.