1- use core:: ops:: ControlFlow ;
21use std:: borrow:: Cow ;
32
4- use rustc_ast:: visit:: Visitor ;
53use rustc_ast:: * ;
64use rustc_data_structures:: fx:: FxIndexMap ;
75use rustc_hir as hir;
@@ -476,77 +474,32 @@ fn expand_format_args<'hir>(
476474 return hir:: ExprKind :: Call ( new, new_args) ;
477475 }
478476
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 ( ) {
491478 // Generate:
492- // &<core::fmt::Argument>::none()
493- //
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- // 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) ) | {
523- let placeholder_span =
524- 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- 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- ) ) ;
534- make_argument ( ctx, placeholder_span, ref_arg, ty)
535- } ,
536- ) ) ;
537- ctx. expr_array_ref ( macsp, elements)
479+ // []
480+ ( None , ctx. arena . alloc ( ctx. expr ( macsp, hir:: ExprKind :: Array ( & [ ] ) ) ) )
538481 } else {
539482 // 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- // }
483+ // super let args = (&arg0, &arg1, &…);
548484 let args_ident = Ident :: new ( sym:: args, macsp) ;
549485 let ( args_pat, args_hir_id) = ctx. pat_ident ( macsp, args_ident) ;
486+ let elements = ctx. arena . alloc_from_iter ( arguments. iter ( ) . map ( |arg| {
487+ let arg_expr = ctx. lower_expr ( & arg. expr ) ;
488+ ctx. expr (
489+ arg. expr . span . with_ctxt ( macsp. ctxt ( ) ) ,
490+ hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , hir:: Mutability :: Not , arg_expr) ,
491+ )
492+ } ) ) ;
493+ let args_tuple = ctx. arena . alloc ( ctx. expr ( macsp, hir:: ExprKind :: Tup ( elements) ) ) ;
494+ let let_statement_1 = ctx. stmt_super_let_pat ( macsp, args_pat, Some ( args_tuple) ) ;
495+
496+ // Generate:
497+ // super let args = [
498+ // <core::fmt::Argument>::new_display(args.0),
499+ // <core::fmt::Argument>::new_lower_hex(args.1),
500+ // <core::fmt::Argument>::new_debug(args.0),
501+ // …
502+ // ];
550503 let args = ctx. arena . alloc_from_iter ( argmap. iter ( ) . map (
551504 |( & ( arg_index, ty) , & placeholder_span) | {
552505 let arg = & arguments[ arg_index] ;
@@ -567,29 +520,21 @@ fn expand_format_args<'hir>(
567520 make_argument ( ctx, placeholder_span, arg, ty)
568521 } ,
569522 ) ) ;
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) ,
523+ let args = ctx. arena . alloc ( ctx. expr ( macsp, hir:: ExprKind :: Array ( args) ) ) ;
524+ let ( args_pat, args_hir_id) = ctx. pat_ident ( macsp, args_ident) ;
525+ let let_statement_2 = ctx. stmt_super_let_pat ( macsp, args_pat, Some ( args) ) ;
526+ (
527+ Some ( [ let_statement_1, let_statement_2] ) ,
528+ ctx. arena . alloc ( ctx. expr_ident_mut ( macsp, args_ident, args_hir_id) ) ,
589529 )
590530 } ;
591531
592- if let Some ( format_options) = format_options {
532+ // Generate:
533+ // &args
534+ let args =
535+ ctx. expr ( macsp, hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , hir:: Mutability :: Not , args) ) ;
536+
537+ let call = if let Some ( format_options) = format_options {
593538 // Generate:
594539 // <core::fmt::Arguments>::new_v1_formatted(
595540 // lit_pieces,
@@ -632,35 +577,21 @@ fn expand_format_args<'hir>(
632577 ) ) ;
633578 let new_args = ctx. arena . alloc_from_iter ( [ lit_pieces, args] ) ;
634579 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- }
580+ } ;
656581
657- fn visit_item ( & mut self , _: & ast:: Item ) -> ControlFlow < ( ) > {
658- // Do not recurse into nested items.
659- ControlFlow :: Continue ( ( ) )
660- }
582+ if let Some ( let_statements) = let_statements {
583+ // Generate:
584+ // {
585+ // super let …
586+ // super let …
587+ // <core::fmt::Arguments>::new_…(…)
588+ // }
589+ let call = ctx. arena . alloc ( ctx. expr ( macsp, call) ) ;
590+ let block = ctx. block_all ( macsp, ctx. arena . alloc_from_iter ( let_statements) , Some ( call) ) ;
591+ hir:: ExprKind :: Block ( block, None )
592+ } else {
593+ call
661594 }
662-
663- MayContainYieldPoint . visit_expr ( e) . is_break ( )
664595}
665596
666597fn for_all_argument_indexes ( template : & mut [ FormatArgsPiece ] , mut f : impl FnMut ( & mut usize ) ) {
0 commit comments