@@ -31,10 +31,10 @@ use crate::transform::MirPass;
3131use  rustc_index:: vec:: { Idx ,  IndexVec } ; 
3232use  rustc_middle:: mir:: visit:: { MutVisitor ,  MutatingUseContext ,  PlaceContext ,  Visitor } ; 
3333use  rustc_middle:: mir:: * ; 
34+ use  rustc_middle:: ty:: ParamEnv ; 
3435use  rustc_middle:: ty:: TyCtxt ; 
3536use  smallvec:: SmallVec ; 
36- use  std:: borrow:: Cow ; 
37- use  std:: convert:: TryInto ; 
37+ use  std:: { borrow:: Cow ,  convert:: TryInto } ; 
3838
3939pub  struct  SimplifyCfg  { 
4040    label :  String , 
@@ -326,7 +326,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
326326
327327pub  fn  simplify_locals < ' tcx > ( body :  & mut  Body < ' tcx > ,  tcx :  TyCtxt < ' tcx > )  { 
328328    // First, we're going to get a count of *actual* uses for every `Local`. 
329-     let  mut  used_locals = UsedLocals :: new ( body) ; 
329+     let  mut  used_locals = UsedLocals :: new ( body,  tcx ) ; 
330330
331331    // Next, we're going to remove any `Local` with zero actual uses. When we remove those 
332332    // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` 
@@ -336,7 +336,8 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
336336    remove_unused_definitions ( & mut  used_locals,  body) ; 
337337
338338    // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. 
339-     let  map = make_local_map ( & mut  body. local_decls ,  & used_locals) ; 
339+     let  arg_count = body. arg_count . try_into ( ) . unwrap ( ) ; 
340+     let  map = make_local_map ( & mut  body. local_decls ,  & used_locals,  arg_count) ; 
340341
341342    // Only bother running the `LocalUpdater` if we actually found locals to remove. 
342343    if  map. iter ( ) . any ( Option :: is_none)  { 
@@ -349,54 +350,61 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
349350} 
350351
351352/// Construct the mapping while swapping out unused stuff out from the `vec`. 
352- fn  make_local_map < V > ( 
353+ fn  make_local_map < ' tcx ,   V > ( 
353354    local_decls :  & mut  IndexVec < Local ,  V > , 
354-     used_locals :  & UsedLocals , 
355+     used_locals :  & UsedLocals < ' tcx > , 
356+     arg_count :  u32 , 
355357)  -> IndexVec < Local ,  Option < Local > >  { 
356-     let  mut  map:  IndexVec < Local ,  Option < Local > >  = IndexVec :: from_elem ( None ,  & * local_decls) ; 
358+     let  mut  map:  IndexVec < Local ,  Option < Local > >  = IndexVec :: from_elem ( None ,  local_decls) ; 
357359    let  mut  used = Local :: new ( 0 ) ; 
358360
359361    for  alive_index in  local_decls. indices ( )  { 
360-         // `is_used` treats the `RETURN_PLACE` and arguments as used. 
361-         if  !used_locals. is_used ( alive_index)  { 
362-             continue ; 
363-         } 
364- 
365-         map[ alive_index]  = Some ( used) ; 
366-         if  alive_index != used { 
367-             local_decls. swap ( alive_index,  used) ; 
362+         // When creating the local map treat the `RETURN_PLACE` and arguments as used. 
363+         if  alive_index. as_u32 ( )  <= arg_count || used_locals. is_used ( alive_index)  { 
364+             map[ alive_index]  = Some ( used) ; 
365+             if  alive_index != used { 
366+                 local_decls. swap ( alive_index,  used) ; 
367+             } 
368+             used. increment_by ( 1 ) ; 
368369        } 
369-         used. increment_by ( 1 ) ; 
370370    } 
371371    local_decls. truncate ( used. index ( ) ) ; 
372372    map
373373} 
374374
375375/// Keeps track of used & unused locals. 
376- struct  UsedLocals  { 
376+ struct  UsedLocals < ' tcx >  { 
377377    increment :  bool , 
378-     arg_count :  u32 , 
379378    use_count :  IndexVec < Local ,  u32 > , 
379+     is_static :  bool , 
380+     local_decls :  IndexVec < Local ,  LocalDecl < ' tcx > > , 
381+     param_env :  ParamEnv < ' tcx > , 
382+     tcx :  TyCtxt < ' tcx > , 
380383} 
381384
382- impl  UsedLocals  { 
385+ impl  UsedLocals < ' tcx >  { 
383386    /// Determines which locals are used & unused in the given body. 
384-      fn  new ( body :  & Body < ' _ > )  -> Self  { 
387+      fn  new ( body :  & Body < ' tcx > ,  tcx :  TyCtxt < ' tcx > )  -> Self  { 
388+         let  def_id = body. source . def_id ( ) ; 
389+         let  is_static = tcx. is_static ( def_id) ; 
390+         let  param_env = tcx. param_env ( def_id) ; 
391+         let  local_decls = body. local_decls . clone ( ) ; 
385392        let  mut  this = Self  { 
386393            increment :  true , 
387-             arg_count :  body. arg_count . try_into ( ) . unwrap ( ) , 
388394            use_count :  IndexVec :: from_elem ( 0 ,  & body. local_decls ) , 
395+             is_static, 
396+             local_decls, 
397+             param_env, 
398+             tcx, 
389399        } ; 
390400        this. visit_body ( body) ; 
391401        this
392402    } 
393403
394404    /// Checks if local is used. 
395-      /// 
396-      /// Return place and arguments are always considered used. 
397405     fn  is_used ( & self ,  local :  Local )  -> bool  { 
398406        trace ! ( "is_used({:?}): use_count: {:?}" ,  local,  self . use_count[ local] ) ; 
399-         local . as_u32 ( )  <=  self . arg_count  ||  self . use_count [ local]  != 0 
407+         self . use_count [ local]  != 0 
400408    } 
401409
402410    /// Updates the use counts to reflect the removal of given statement. 
@@ -424,7 +432,7 @@ impl UsedLocals {
424432    } 
425433} 
426434
427- impl  Visitor < ' _ >  for  UsedLocals  { 
435+ impl  Visitor < ' tcx >  for  UsedLocals < ' tcx >  { 
428436    fn  visit_statement ( & mut  self ,  statement :  & Statement < ' tcx > ,  location :  Location )  { 
429437        match  statement. kind  { 
430438            StatementKind :: LlvmInlineAsm ( ..) 
@@ -451,7 +459,21 @@ impl Visitor<'_> for UsedLocals {
451459        } 
452460    } 
453461
454-     fn  visit_local ( & mut  self ,  local :  & Local ,  _ctx :  PlaceContext ,  _location :  Location )  { 
462+     fn  visit_local ( & mut  self ,  local :  & Local ,  ctx :  PlaceContext ,  _location :  Location )  { 
463+         debug ! ( "local: {:?} is_static: {:?}, ctx: {:?}" ,  local,  self . is_static,  ctx) ; 
464+         // Do not count _0 as a used in `return;` if it is a ZST. 
465+         let  return_place = * local == RETURN_PLACE 
466+             && matches ! ( ctx,  PlaceContext :: NonMutatingUse ( visit:: NonMutatingUseContext :: Move ) ) ; 
467+         if  !self . is_static  && return_place { 
468+             let  ty = self . local_decls [ * local] . ty ; 
469+             let  param_env_and = self . param_env . and ( ty) ; 
470+             if  let  Ok ( layout)  = self . tcx . layout_of ( param_env_and)  { 
471+                 debug ! ( "layout.is_zst: {:?}" ,  layout. is_zst( ) ) ; 
472+                 if  layout. is_zst ( )  { 
473+                     return ; 
474+                 } 
475+             } 
476+         } 
455477        if  self . increment  { 
456478            self . use_count [ * local]  += 1 ; 
457479        }  else  { 
@@ -462,7 +484,10 @@ impl Visitor<'_> for UsedLocals {
462484} 
463485
464486/// Removes unused definitions. Updates the used locals to reflect the changes made. 
465- fn  remove_unused_definitions < ' a ,  ' tcx > ( used_locals :  & ' a  mut  UsedLocals ,  body :  & mut  Body < ' tcx > )  { 
487+ fn  remove_unused_definitions < ' a ,  ' tcx > ( 
488+     used_locals :  & ' a  mut  UsedLocals < ' tcx > , 
489+     body :  & mut  Body < ' tcx > , 
490+ )  { 
466491    // The use counts are updated as we remove the statements. A local might become unused 
467492    // during the retain operation, leading to a temporary inconsistency (storage statements or 
468493    // definitions referencing the local might remain). For correctness it is crucial that this 
0 commit comments