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,52 @@ 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()
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.
493483 //
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 {
514484 // 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] ;
523489 let placeholder_span =
524490 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- } ;
529491 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) ) ;
534493 make_argument ( ctx, placeholder_span, ref_arg, ty)
535494 } ,
536495 ) ) ;
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) ) )
538501 } else {
539502 // 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, &…);
548504 let args_ident = Ident :: new ( sym:: args, macsp) ;
549505 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+ // ];
550523 let args = ctx. arena . alloc_from_iter ( argmap. iter ( ) . map (
551524 |( & ( arg_index, ty) , & placeholder_span) | {
552525 let arg = & arguments[ arg_index] ;
@@ -567,58 +540,48 @@ fn expand_format_args<'hir>(
567540 make_argument ( ctx, placeholder_span, arg, ty)
568541 } ,
569542 ) ) ;
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) ) ,
589549 )
590550 } ;
591551
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 {
593558 // 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+ // }
600566 let new_v1_formatted = ctx. arena . alloc ( ctx. expr_lang_item_type_relative (
601567 macsp,
602568 hir:: LangItem :: FormatArguments ,
603569 sym:: new_v1_formatted,
604570 ) ) ;
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) ;
611573 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+ )
622585 } else {
623586 // Generate:
624587 // <core::fmt::Arguments>::new_v1(
@@ -632,35 +595,21 @@ fn expand_format_args<'hir>(
632595 ) ) ;
633596 let new_args = ctx. arena . alloc_from_iter ( [ lit_pieces, args] ) ;
634597 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+ } ;
656599
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
661612 }
662-
663- MayContainYieldPoint . visit_expr ( e) . is_break ( )
664613}
665614
666615fn for_all_argument_indexes ( template : & mut [ FormatArgsPiece ] , mut f : impl FnMut ( & mut usize ) ) {
0 commit comments