Skip to content

Commit be1ea4b

Browse files
committed
Use str::to_owned for format! without formatting arguments
1 parent b836329 commit be1ea4b

File tree

6 files changed

+116
-33
lines changed

6 files changed

+116
-33
lines changed

Diff for: library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
#![feature(exact_size_is_empty)]
9898
#![feature(exclusive_range_pattern)]
9999
#![feature(extend_one)]
100+
#![feature(fmt_as_str)]
100101
#![feature(fmt_internals)]
101102
#![feature(fn_traits)]
102103
#![feature(fundamental)]

Diff for: library/alloc/src/macros.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,21 @@ macro_rules! vec {
101101
/// ```
102102
#[macro_export]
103103
#[stable(feature = "rust1", since = "1.0.0")]
104+
#[allow_internal_unstable(fmt_as_str)]
104105
macro_rules! format {
105106
($($arg:tt)*) => {{
106-
let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
107-
res
107+
// NOTE: `format_args!` borrows from temporaries. This means that
108+
// `match` is necessary to extend the lifetime of the temporaries until after
109+
// the `Arguments` is no longer used. The same pattern is used
110+
// inside `format_args!` itself.
111+
let r = match $crate::__export::format_args!($($arg)*) {
112+
// HACK: We hope that constant propagation will make LLVM optimize out
113+
// this match.
114+
args => match args.as_str() {
115+
Some(s) => $crate::borrow::ToOwned::to_owned(s),
116+
None => $crate::fmt::format(args),
117+
}
118+
};
119+
r
108120
}}
109121
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// min-llvm-version: 10.0.0
2+
// compile-flags: -C opt-level=3
3+
#![crate_type = "rlib"]
4+
#![feature(format_args_capture)]
5+
6+
// Make sure allocation not happen when result of `format!` is unused and
7+
// there are no formatting arguments.
8+
9+
// CHECK-LABEL: @format_wo_fmt_args
10+
// CHECK-NEXT: {{"_ZN[^:]+"}}:
11+
// CHECK-NEXT: ret
12+
#[no_mangle]
13+
pub fn format_wo_fmt_args() {
14+
format!("");
15+
format!("a long story");
16+
format!("a long story {{");
17+
}
18+
19+
// CHECK-LABEL: @format_wo_fmt_args_ret
20+
// CHECK-NOT: Arguments
21+
#[no_mangle]
22+
pub fn format_wo_fmt_args_ret() -> String {
23+
format!("a long story")
24+
}
25+
26+
// CHECK-LABEL: @format_w_fmt_args_ret_1
27+
// CHECK: alloc::fmt::format
28+
#[no_mangle]
29+
pub fn format_w_fmt_args_ret_1(n: usize) -> String {
30+
format!("a long story: {}", n)
31+
}
32+
33+
// CHECK-LABEL: @format_w_fmt_args_ret_2
34+
// CHECK: core::fmt::ArgumentV1::from_usize
35+
// CHECK: alloc::fmt::format
36+
#[no_mangle]
37+
pub fn format_w_fmt_args_ret_2(n: usize, width: usize) -> String {
38+
format!("a long story {n:width$}")
39+
}

Diff for: src/test/pretty/issue-4264.pp

+42-29
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,48 @@
3030

3131

3232
({
33-
let res =
34-
((::alloc::fmt::format as
35-
for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
36-
as
37-
fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
38-
as
39-
&str)]
40-
as
41-
[&str; 1])
42-
as
43-
&[&str; 1]),
44-
(&(match (()
45-
as
46-
())
47-
{
48-
()
49-
=>
50-
([]
51-
as
52-
[ArgumentV1; 0]),
53-
}
54-
as
55-
[ArgumentV1; 0])
56-
as
57-
&[ArgumentV1; 0]))
58-
as
59-
Arguments))
60-
as String);
61-
(res as String)
33+
let r =
34+
(match ((::core::fmt::Arguments::new_v1 as
35+
fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
36+
as
37+
&str)]
38+
as
39+
[&str; 1])
40+
as
41+
&[&str; 1]),
42+
(&(match (()
43+
as
44+
())
45+
{
46+
()
47+
=>
48+
([]
49+
as
50+
[ArgumentV1; 0]),
51+
}
52+
as
53+
[ArgumentV1; 0])
54+
as
55+
&[ArgumentV1; 0]))
56+
as Arguments) {
57+
args =>
58+
(match ((args as Arguments).as_str() as
59+
Option<&str>) {
60+
Some(s) =>
61+
((::alloc::borrow::ToOwned::to_owned as
62+
for<'r> fn(&'r str) -> <str as ToOwned>::Owned {<str as ToOwned>::to_owned})((s
63+
as
64+
&str))
65+
as String),
66+
None =>
67+
((::alloc::fmt::format as
68+
for<'r> fn(Arguments<'r>) -> String {format})((args
69+
as
70+
Arguments))
71+
as String),
72+
} as String),
73+
} as String);
74+
(r as String)
6275
} as String);
6376
} as ())
6477
pub type Foo = [i32; (3 as usize)];

Diff for: src/test/ui/borrowck/issue-64453.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ struct Value;
44
static settings_dir: String = format!("");
55
//~^ ERROR calls in statics are limited to constant functions
66
//~| ERROR calls in statics are limited to constant functions
7+
//~| ERROR calls in statics are limited to constant functions
8+
//~| ERROR calls in statics are limited to constant functions
79

810
fn from_string(_: String) -> Value {
911
Value

Diff for: src/test/ui/borrowck/issue-64453.stderr

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0507]: cannot move out of static item `settings_dir`
2-
--> $DIR/issue-64453.rs:14:37
2+
--> $DIR/issue-64453.rs:16:37
33
|
44
LL | let settings_data = from_string(settings_dir);
55
| ^^^^^^^^^^^^ 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!("");
2020
|
2121
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
2222

23-
error: aborting due to 3 previous errors
23+
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
24+
--> $DIR/issue-64453.rs:4:31
25+
|
26+
LL | static settings_dir: String = format!("");
27+
| ^^^^^^^^^^^
28+
|
29+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
30+
31+
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
32+
--> $DIR/issue-64453.rs:4:31
33+
|
34+
LL | static settings_dir: String = format!("");
35+
| ^^^^^^^^^^^
36+
|
37+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
38+
39+
error: aborting due to 5 previous errors
2440

2541
Some errors have detailed explanations: E0015, E0507.
2642
For more information about an error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)