1
- use core::ops::ControlFlow;
2
1
use std::borrow::Cow;
3
2
4
- use rustc_ast::visit::Visitor;
5
3
use rustc_ast::*;
6
4
use rustc_data_structures::fx::FxIndexMap;
7
5
use rustc_hir as hir;
@@ -476,77 +474,52 @@ fn expand_format_args<'hir>(
476
474
return hir::ExprKind::Call(new, new_args);
477
475
}
478
476
479
- // If the args array contains exactly all the original arguments once,
480
- // in order, we can use a simple array instead of a `match` construction.
481
- // However, if there's a yield point in any argument except the first one,
482
- // we don't do this, because an Argument cannot be kept across yield points.
483
- //
484
- // This is an optimization, speeding up compilation about 1-2% in some cases.
485
- // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
486
- let use_simple_array = argmap.len() == arguments.len()
487
- && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j)
488
- && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
489
-
490
- let args = if arguments.is_empty() {
477
+ let (let_statements, args) = if arguments.is_empty() {
491
478
// Generate:
492
- // &<core::fmt::Argument>::none()
479
+ // []
480
+ (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[]))))
481
+ } else if argmap.len() == 1 && arguments.len() == 1 {
482
+ // Only one argument, so we don't need to make the `args` tuple.
493
483
//
494
- // Note:
495
- // `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime.
496
- //
497
- // This makes sure that this still fails to compile, even when the argument is inlined:
498
- //
499
- // ```
500
- // let f = format_args!("{}", "a");
501
- // println!("{f}"); // error E0716
502
- // ```
503
- //
504
- // Cases where keeping the object around is allowed, such as `format_args!("a")`,
505
- // are handled above by the `allow_const` case.
506
- let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
507
- macsp,
508
- hir::LangItem::FormatArgument,
509
- sym::none,
510
- ));
511
- let none = ctx.expr_call(macsp, none_fn, &[]);
512
- ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none))
513
- } else if use_simple_array {
514
484
// Generate:
515
- // &[
516
- // <core::fmt::Argument>::new_display(&arg0),
517
- // <core::fmt::Argument>::new_lower_hex(&arg1),
518
- // <core::fmt::Argument>::new_debug(&arg2),
519
- // …
520
- // ]
521
- let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map(
522
- |(arg, ((_, ty), placeholder_span))| {
485
+ // super let args = [<core::fmt::Argument>::new_display(&arg)];
486
+ let args = ctx.arena.alloc_from_iter(argmap.iter().map(
487
+ |(&(arg_index, ty), &placeholder_span)| {
488
+ let arg = &arguments[arg_index];
523
489
let placeholder_span =
524
490
placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
525
- let arg_span = match arg.kind {
526
- FormatArgumentKind::Captured(_) => placeholder_span,
527
- _ => arg.expr.span.with_ctxt(macsp.ctxt()),
528
- };
529
491
let arg = ctx.lower_expr(&arg.expr);
530
- let ref_arg = ctx.arena.alloc(ctx.expr(
531
- arg_span,
532
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
533
- ));
492
+ let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg));
534
493
make_argument(ctx, placeholder_span, ref_arg, ty)
535
494
},
536
495
));
537
- ctx.expr_array_ref(macsp, elements)
496
+ let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
497
+ let args_ident = Ident::new(sym::args, macsp);
498
+ let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
499
+ let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
500
+ (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)))
538
501
} else {
539
502
// Generate:
540
- // &match (&arg0, &arg1, &…) {
541
- // args => [
542
- // <core::fmt::Argument>::new_display(args.0),
543
- // <core::fmt::Argument>::new_lower_hex(args.1),
544
- // <core::fmt::Argument>::new_debug(args.0),
545
- // …
546
- // ]
547
- // }
503
+ // super let args = (&arg0, &arg1, &…);
548
504
let args_ident = Ident::new(sym::args, macsp);
549
505
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
506
+ let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
507
+ let arg_expr = ctx.lower_expr(&arg.expr);
508
+ ctx.expr(
509
+ arg.expr.span.with_ctxt(macsp.ctxt()),
510
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
511
+ )
512
+ }));
513
+ let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
514
+ let let_statement_1 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args_tuple));
515
+
516
+ // Generate:
517
+ // super let args = [
518
+ // <core::fmt::Argument>::new_display(args.0),
519
+ // <core::fmt::Argument>::new_lower_hex(args.1),
520
+ // <core::fmt::Argument>::new_debug(args.0),
521
+ // …
522
+ // ];
550
523
let args = ctx.arena.alloc_from_iter(argmap.iter().map(
551
524
|(&(arg_index, ty), &placeholder_span)| {
552
525
let arg = &arguments[arg_index];
@@ -567,58 +540,47 @@ fn expand_format_args<'hir>(
567
540
make_argument(ctx, placeholder_span, arg, ty)
568
541
},
569
542
));
570
- let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
571
- let arg_expr = ctx.lower_expr(&arg.expr);
572
- ctx.expr(
573
- arg.expr.span.with_ctxt(macsp.ctxt()),
574
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
575
- )
576
- }));
577
- let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
578
- let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
579
- let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
580
- let match_expr = ctx.arena.alloc(ctx.expr_match(
581
- macsp,
582
- args_tuple,
583
- match_arms,
584
- hir::MatchSource::FormatArgs,
585
- ));
586
- ctx.expr(
587
- macsp,
588
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
543
+ let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
544
+ let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
545
+ let let_statement_2 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
546
+ (
547
+ vec![let_statement_1, let_statement_2],
548
+ ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)),
589
549
)
590
550
};
591
551
592
- if let Some(format_options) = format_options {
552
+ // Generate:
553
+ // &args
554
+ let args = ctx.expr_ref(macsp, args);
555
+
556
+ let call = if let Some(format_options) = format_options {
593
557
// Generate:
594
- // <core::fmt::Arguments>::new_v1_formatted(
595
- // lit_pieces,
596
- // args,
597
- // format_options,
598
- // unsafe { ::core::fmt::UnsafeArg::new() }
599
- // )
558
+ // unsafe {
559
+ // <core::fmt::Arguments>::new_v1_formatted(
560
+ // lit_pieces,
561
+ // args,
562
+ // format_options,
563
+ // )
564
+ // }
600
565
let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
601
566
macsp,
602
567
hir::LangItem::FormatArguments,
603
568
sym::new_v1_formatted,
604
569
));
605
- let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
606
- macsp,
607
- hir::LangItem::FormatUnsafeArg,
608
- sym::new,
609
- ));
610
- let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
570
+ let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options]);
571
+ let call = ctx.expr_call(macsp, new_v1_formatted, args);
611
572
let hir_id = ctx.next_id();
612
- let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
613
- stmts: &[],
614
- expr: Some(unsafe_arg_new_call),
615
- hir_id,
616
- rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
617
- span: macsp,
618
- targeted_by_break: false,
619
- }));
620
- let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
621
- hir::ExprKind::Call(new_v1_formatted, args)
573
+ hir::ExprKind::Block(
574
+ ctx.arena.alloc(hir::Block {
575
+ stmts: &[],
576
+ expr: Some(call),
577
+ hir_id,
578
+ rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
579
+ span: macsp,
580
+ targeted_by_break: false,
581
+ }),
582
+ None,
583
+ )
622
584
} else {
623
585
// Generate:
624
586
// <core::fmt::Arguments>::new_v1(
@@ -632,35 +594,21 @@ fn expand_format_args<'hir>(
632
594
));
633
595
let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
634
596
hir::ExprKind::Call(new_v1, new_args)
635
- }
636
- }
637
-
638
- fn may_contain_yield_point(e: &ast::Expr) -> bool {
639
- struct MayContainYieldPoint;
640
-
641
- impl Visitor<'_> for MayContainYieldPoint {
642
- type Result = ControlFlow<()>;
643
-
644
- fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
645
- if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
646
- ControlFlow::Break(())
647
- } else {
648
- visit::walk_expr(self, e)
649
- }
650
- }
651
-
652
- fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
653
- // Macros should be expanded at this point.
654
- unreachable!("unexpanded macro in ast lowering");
655
- }
597
+ };
656
598
657
- fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
658
- // Do not recurse into nested items.
659
- ControlFlow::Continue(())
660
- }
599
+ if !let_statements.is_empty() {
600
+ // Generate:
601
+ // {
602
+ // super let …
603
+ // super let …
604
+ // <core::fmt::Arguments>::new_…(…)
605
+ // }
606
+ let call = ctx.arena.alloc(ctx.expr(macsp, call));
607
+ let block = ctx.block_all(macsp, ctx.arena.alloc_from_iter(let_statements), Some(call));
608
+ hir::ExprKind::Block(block, None)
609
+ } else {
610
+ call
661
611
}
662
-
663
- MayContainYieldPoint.visit_expr(e).is_break()
664
612
}
665
613
666
614
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
0 commit comments