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 , 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,48 @@ 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 =
555
+ ctx. expr ( macsp, hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , hir:: Mutability :: Not , args) ) ;
556
+
557
+ let call = if let Some ( format_options) = format_options {
593
558
// Generate:
594
- // <core::fmt::Arguments>::new_v1_formatted(
595
- // lit_pieces,
596
- // args,
597
- // format_options,
598
- // unsafe { ::core::fmt::UnsafeArg::new() }
599
- // )
559
+ // unsafe {
560
+ // <core::fmt::Arguments>::new_v1_formatted(
561
+ // lit_pieces,
562
+ // args,
563
+ // format_options,
564
+ // )
565
+ // }
600
566
let new_v1_formatted = ctx. arena . alloc ( ctx. expr_lang_item_type_relative (
601
567
macsp,
602
568
hir:: LangItem :: FormatArguments ,
603
569
sym:: new_v1_formatted,
604
570
) ) ;
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, & [ ] ) ;
571
+ let args = ctx. arena . alloc_from_iter ( [ lit_pieces, args, format_options] ) ;
572
+ let call = ctx. expr_call ( macsp, new_v1_formatted, args) ;
611
573
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)
574
+ hir:: ExprKind :: Block (
575
+ ctx. arena . alloc ( hir:: Block {
576
+ stmts : & [ ] ,
577
+ expr : Some ( call) ,
578
+ hir_id,
579
+ rules : hir:: BlockCheckMode :: UnsafeBlock ( hir:: UnsafeSource :: CompilerGenerated ) ,
580
+ span : macsp,
581
+ targeted_by_break : false ,
582
+ } ) ,
583
+ None ,
584
+ )
622
585
} else {
623
586
// Generate:
624
587
// <core::fmt::Arguments>::new_v1(
@@ -632,35 +595,21 @@ fn expand_format_args<'hir>(
632
595
) ) ;
633
596
let new_args = ctx. arena . alloc_from_iter ( [ lit_pieces, args] ) ;
634
597
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
- }
598
+ } ;
656
599
657
- fn visit_item ( & mut self , _: & ast:: Item ) -> ControlFlow < ( ) > {
658
- // Do not recurse into nested items.
659
- ControlFlow :: Continue ( ( ) )
660
- }
600
+ if !let_statements. is_empty ( ) {
601
+ // Generate:
602
+ // {
603
+ // super let …
604
+ // super let …
605
+ // <core::fmt::Arguments>::new_…(…)
606
+ // }
607
+ let call = ctx. arena . alloc ( ctx. expr ( macsp, call) ) ;
608
+ let block = ctx. block_all ( macsp, ctx. arena . alloc_from_iter ( let_statements) , Some ( call) ) ;
609
+ hir:: ExprKind :: Block ( block, None )
610
+ } else {
611
+ call
661
612
}
662
-
663
- MayContainYieldPoint . visit_expr ( e) . is_break ( )
664
613
}
665
614
666
615
fn for_all_argument_indexes ( template : & mut [ FormatArgsPiece ] , mut f : impl FnMut ( & mut usize ) ) {
0 commit comments