Skip to content

Commit 5f1950c

Browse files
committed
Update fmt::Arguments closure to take dyn Write.
Using a new Formatter for every fmt invocation allows the compiler to make assumptions about the state of the formatting flags.
1 parent ba9001a commit 5f1950c

File tree

4 files changed

+63
-33
lines changed

4 files changed

+63
-33
lines changed

compiler/rustc_builtin_macros/src/format/expand.rs

+51-26
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,24 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
2222
}
2323

2424
let args = Ident::new(sym::_args, macsp);
25-
let f = Ident::new(sym::f, macsp);
25+
let w = Ident::new(sym::w, macsp);
2626

2727
let arguments = fmt.arguments.into_vec();
2828

2929
let mut statements = Vec::new();
3030

31-
let mut default_options = true;
32-
3331
for piece in fmt.template {
3432
match piece {
3533
FormatArgsPiece::Literal(s) => {
3634
// Generate:
37-
// f.write_str("…")?;
35+
// w.write_str("…")?;
3836
statements.push(ecx.stmt_expr(ecx.expr(
3937
macsp,
4038
ast::ExprKind::Try(ecx.expr(
4139
macsp,
4240
ast::ExprKind::MethodCall(
4341
ast::PathSegment::from_ident(Ident::new(sym::write_str, macsp)),
44-
ecx.expr_ident(macsp, f),
42+
ecx.expr_ident(macsp, w),
4543
vec![ecx.expr_str(macsp, s)],
4644
macsp,
4745
),
@@ -51,16 +49,23 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
5149
FormatArgsPiece::Placeholder(p) => {
5250
// Don't set options if they're still set to defaults
5351
// and this placeholder also uses default options.
54-
let d = p.format_options == FormatOptions::default();
55-
if !default_options || !d {
56-
default_options = d;
57-
// Generate:
58-
// f.set_options(…);
59-
statements.push(ecx.stmt_expr(ecx.expr(
52+
53+
// Generate:
54+
// ::core::fmt::Formatter::new(w)
55+
let mut formatter = ecx.expr_call_global(
56+
macsp,
57+
ecx.std_path(&[sym::fmt, sym::Formatter, sym::new]),
58+
vec![ecx.expr_ident(macsp, w)],
59+
);
60+
61+
if p.format_options != FormatOptions::default() {
62+
// Add:
63+
// .with_options(…)
64+
formatter = ecx.expr(
6065
macsp,
6166
ast::ExprKind::MethodCall(
62-
ast::PathSegment::from_ident(Ident::new(sym::set_options, macsp)),
63-
ecx.expr_ident(macsp, f),
67+
ast::PathSegment::from_ident(Ident::new(sym::with_options, macsp)),
68+
formatter,
6469
vec![
6570
ecx.expr_u32(macsp, p.format_options.flags),
6671
ecx.expr_char(macsp, p.format_options.fill.unwrap_or(' ')),
@@ -90,10 +95,12 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
9095
],
9196
macsp,
9297
),
93-
)));
98+
);
9499
}
100+
95101
// Generate:
96-
// ::core::fmt::Display::fmt(arg.0, f)?;
102+
// ::core::fmt::Display::fmt(arg.0, &mut formatter)?;
103+
97104
let arg = if let Ok(i) = p.argument.index {
98105
ecx.expr_field(
99106
arguments[i].expr.span.with_ctxt(macsp.ctxt()),
@@ -119,7 +126,17 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
119126
ast::ExprKind::Try(ecx.expr_call_global(
120127
arg.span,
121128
ecx.std_path(&[sym::fmt, fmt_trait, sym::fmt]),
122-
vec![arg, ecx.expr_ident(macsp, f)],
129+
vec![
130+
arg,
131+
ecx.expr(
132+
macsp,
133+
ast::ExprKind::AddrOf(
134+
ast::BorrowKind::Ref,
135+
ast::Mutability::Mut,
136+
formatter,
137+
),
138+
),
139+
],
123140
)),
124141
)));
125142
}
@@ -131,7 +148,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
131148
statements.push(ecx.stmt_expr(ecx.expr_ok(macsp, ecx.expr_tuple(macsp, Vec::new()))));
132149

133150
// Generate:
134-
// |f: &mut ::core::fmt::Formatter| -> ::core::fmt::Result {
151+
// |w: &mut dyn ::core::fmt::Write| -> ::core::fmt::Result {
135152
// … // statements
136153
// }
137154
let closure = ecx.expr(
@@ -144,18 +161,26 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
144161
ecx.fn_decl(
145162
vec![ecx.param(
146163
macsp,
147-
f,
164+
w,
148165
ecx.ty_rptr(
149166
macsp,
150-
ecx.ty_path(ecx.path_all(
167+
ecx.ty(
151168
macsp,
152-
true,
153-
ecx.std_path(&[sym::fmt, sym::Formatter]),
154-
vec![ast::GenericArg::Lifetime(ast::Lifetime {
155-
id: ast::DUMMY_NODE_ID,
156-
ident: Ident::new(kw::UnderscoreLifetime, macsp),
157-
})],
158-
)),
169+
ast::TyKind::TraitObject(
170+
vec![ast::GenericBound::Trait(
171+
ast::PolyTraitRef::new(
172+
vec![],
173+
ecx.path_global(
174+
macsp,
175+
ecx.std_path(&[sym::fmt, sym::Write]),
176+
),
177+
macsp,
178+
),
179+
ast::TraitBoundModifier::None,
180+
)],
181+
ast::TraitObjectSyntax::Dyn,
182+
),
183+
),
159184
None,
160185
ast::Mutability::Mut,
161186
),

compiler/rustc_span/src/symbol.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ symbols! {
308308
Vec,
309309
VecDeque,
310310
Wrapper,
311+
Write,
311312
Yield,
312313
_DECLS,
313314
_Self,
@@ -1325,7 +1326,6 @@ symbols! {
13251326
self_in_typedefs,
13261327
self_struct_ctor,
13271328
semitransparent,
1328-
set_options,
13291329
shadow_call_stack,
13301330
shl,
13311331
shl_assign,
@@ -1620,6 +1620,7 @@ symbols! {
16201620
vreg_low16,
16211621
vtable_align,
16221622
vtable_size,
1623+
w,
16231624
warn,
16241625
wasm_abi,
16251626
wasm_import_module,
@@ -1629,6 +1630,7 @@ symbols! {
16291630
windows,
16301631
windows_subsystem,
16311632
with_negative_coherence,
1633+
with_options,
16321634
wrapping_add,
16331635
wrapping_mul,
16341636
wrapping_sub,

library/core/src/fmt/mod.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -261,19 +261,20 @@ impl<'a> Formatter<'a> {
261261
#[unstable(feature = "fmt_internals", issue = "none")]
262262
#[doc(hidden)]
263263
#[inline]
264-
pub fn set_options(
265-
&mut self,
264+
pub fn with_options(
265+
mut self,
266266
flags: u32,
267267
fill: char,
268268
align: rt::v1::Alignment,
269269
width: Option<usize>,
270270
precision: Option<usize>,
271-
) {
271+
) -> Self {
272272
self.flags = flags;
273273
self.fill = fill;
274274
self.align = align;
275275
self.width = width;
276276
self.precision = precision;
277+
self
277278
}
278279
}
279280

@@ -460,7 +461,7 @@ impl<'a> Arguments<'a> {
460461
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
461462
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
462463
#[cfg(not(bootstrap))]
463-
pub const fn new(f: &'a dyn Fn(&mut Formatter<'_>) -> Result) -> Arguments<'a> {
464+
pub const fn new(f: &'a dyn Fn(&mut dyn Write) -> Result) -> Arguments<'a> {
464465
Arguments { inner: Inner::Fn(f) }
465466
}
466467

@@ -545,7 +546,7 @@ pub struct Arguments<'a> {
545546
#[cfg(not(bootstrap))]
546547
#[derive(Copy, Clone)]
547548
enum Inner<'a> {
548-
Fn(&'a dyn Fn(&mut Formatter<'_>) -> Result),
549+
Fn(&'a dyn Fn(&mut dyn Write) -> Result),
549550
StaticStr(&'static str),
550551
}
551552

@@ -1286,7 +1287,7 @@ pub trait UpperExp {
12861287
#[inline]
12871288
pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
12881289
match args.inner {
1289-
Inner::Fn(f) => f(&mut Formatter::new(output)),
1290+
Inner::Fn(f) => f(output),
12901291
Inner::StaticStr(s) => output.write_str(s),
12911292
}
12921293
}

library/std/src/io/stdio.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,7 @@ where
10261026
)]
10271027
#[doc(hidden)]
10281028
#[cfg(not(test))]
1029+
#[inline]
10291030
pub fn _print(args: fmt::Arguments<'_>) {
10301031
print_to(args, stdout, "stdout");
10311032
}
@@ -1037,6 +1038,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
10371038
)]
10381039
#[doc(hidden)]
10391040
#[cfg(not(test))]
1041+
#[inline]
10401042
pub fn _eprint(args: fmt::Arguments<'_>) {
10411043
print_to(args, stderr, "stderr");
10421044
}

0 commit comments

Comments
 (0)