11use std:: borrow:: Cow ;
22
33use rustc_ast:: * ;
4- use rustc_data_structures:: fx:: FxIndexMap ;
4+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
55use rustc_hir as hir;
66use rustc_session:: config:: FmtDebug ;
77use rustc_span:: { ByteSymbol , DesugaringKind , Ident , Span , Symbol , sym} ;
8+ use smallvec:: SmallVec ;
89
910use super :: LoweringContext ;
1011
@@ -290,6 +291,7 @@ fn expand_format_args<'hir>(
290291 // We use usize::MAX for arguments that don't exist, because that can never be a valid index
291292 // into the arguments array.
292293 let mut argmap = FxIndexMap :: default ( ) ;
294+ let mut might_be_const_capture_dups = FxIndexMap :: default ( ) ;
293295
294296 let mut incomplete_lit = String :: new ( ) ;
295297
@@ -307,6 +309,8 @@ fn expand_format_args<'hir>(
307309
308310 // See library/core/src/fmt/mod.rs for the format string encoding format.
309311
312+ let arguments = fmt. arguments . all_args ( ) ;
313+
310314 for ( i, piece) in template. iter ( ) . enumerate ( ) {
311315 match piece {
312316 & FormatArgsPiece :: Literal ( sym) => {
@@ -370,6 +374,16 @@ fn expand_format_args<'hir>(
370374 )
371375 . 0 as u64 ;
372376
377+ if matches ! ( p. argument. kind, FormatArgPositionKind :: Named )
378+ && let Some ( arg) = arguments. get ( p. argument . index . unwrap_or ( usize:: MAX ) )
379+ && matches ! ( arg. kind, FormatArgumentKind :: Captured ( _) )
380+ {
381+ let dups = might_be_const_capture_dups
382+ . entry ( p. argument . index . unwrap_or ( usize:: MAX ) )
383+ . or_insert_with ( || ( arg, SmallVec :: < [ _ ; 1 ] > :: with_capacity ( 1 ) ) ) ;
384+ dups. 1 . push ( p. span ) ;
385+ }
386+
373387 // This needs to match the constants in library/core/src/fmt/mod.rs.
374388 let o = & p. format_options ;
375389 let align = match o. alignment {
@@ -428,8 +442,6 @@ fn expand_format_args<'hir>(
428442 ctx. dcx ( ) . span_err ( macsp, "too many format arguments" ) ;
429443 }
430444
431- let arguments = fmt. arguments . all_args ( ) ;
432-
433445 let ( let_statements, args) = if arguments. is_empty ( ) {
434446 // Generate:
435447 // []
@@ -439,8 +451,10 @@ fn expand_format_args<'hir>(
439451 // super let args = (&arg0, &arg1, &…);
440452 let args_ident = Ident :: new ( sym:: args, macsp) ;
441453 let ( args_pat, args_hir_id) = ctx. pat_ident ( macsp, args_ident) ;
454+ let mut arg_exprs = FxHashMap :: default ( ) ;
442455 let elements = ctx. arena . alloc_from_iter ( arguments. iter ( ) . map ( |arg| {
443456 let arg_expr = ctx. lower_expr ( & arg. expr ) ;
457+ arg_exprs. insert ( arg. expr . node_id ( ) , arg_expr) ;
444458 ctx. expr (
445459 arg. expr . span . with_ctxt ( macsp. ctxt ( ) ) ,
446460 hir:: ExprKind :: AddrOf ( hir:: BorrowKind :: Ref , hir:: Mutability :: Not , arg_expr) ,
@@ -487,10 +501,51 @@ fn expand_format_args<'hir>(
487501 let args = ctx. arena . alloc ( ctx. expr ( macsp, hir:: ExprKind :: Array ( args) ) ) ;
488502 let ( args_pat, args_hir_id) = ctx. pat_ident ( macsp, args_ident) ;
489503 let let_statement_2 = ctx. stmt_super_let_pat ( macsp, args_pat, Some ( args) ) ;
490- (
491- vec ! [ let_statement_1, let_statement_2] ,
492- ctx. arena . alloc ( ctx. expr_ident_mut ( macsp, args_ident, args_hir_id) ) ,
493- )
504+
505+ let mut let_statements = vec ! [ let_statement_1, let_statement_2] ;
506+
507+ // Generate:
508+ // let __issue_145739 = (&x, (), (), ..);
509+ // as many times as the number of duplicated captured arguments.
510+ // These will be scrutinized with late lints for crater run for #145739
511+ if might_be_const_capture_dups. values ( ) . any ( |v| v. 1 . len ( ) > 1 ) {
512+ for ( arg, dups) in might_be_const_capture_dups. values ( ) . filter ( |v| v. 1 . len ( ) > 1 ) {
513+ let Some ( & arg_expr) = arg_exprs. get ( & arg. expr . node_id ( ) ) else { continue } ;
514+ // HACK: In general, this would cause weird ICEs with nested expressions but okay in
515+ // here since the arg here is a simple path.
516+ let arg_expr = ctx. arena . alloc ( ctx. expr ( arg_expr. span , arg_expr. kind . clone ( ) ) ) ;
517+ let dups_ident = Ident :: new ( sym:: __issue_145739, arg. expr . span ) ;
518+ let ( dups_pat, _) = ctx. pat_ident ( arg. expr . span , dups_ident) ;
519+ let elements = ctx. arena . alloc_from_iter (
520+ std:: iter:: once ( {
521+ ctx. expr (
522+ arg. expr . span . with_ctxt ( macsp. ctxt ( ) ) ,
523+ hir:: ExprKind :: AddrOf (
524+ hir:: BorrowKind :: Ref ,
525+ hir:: Mutability :: Not ,
526+ arg_expr,
527+ ) ,
528+ )
529+ } )
530+ . chain ( dups. iter ( ) . map ( |sp| {
531+ let sp = sp. unwrap_or ( arg. expr . span ) . with_ctxt ( macsp. ctxt ( ) ) ;
532+ ctx. expr ( sp, hir:: ExprKind :: Tup ( & [ ] ) )
533+ } ) ) ,
534+ ) ;
535+ let dups_tuple =
536+ ctx. arena . alloc ( ctx. expr ( arg. expr . span , hir:: ExprKind :: Tup ( elements) ) ) ;
537+ let let_statement = ctx. stmt_let_pat (
538+ None ,
539+ arg. expr . span ,
540+ Some ( dups_tuple) ,
541+ dups_pat,
542+ hir:: LocalSource :: Normal ,
543+ ) ;
544+ let_statements. push ( let_statement) ;
545+ }
546+ }
547+
548+ ( let_statements, ctx. arena . alloc ( ctx. expr_ident_mut ( macsp, args_ident, args_hir_id) ) )
494549 } ;
495550
496551 // Generate:
0 commit comments