@@ -176,24 +176,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
176176
177177 let mut mir = tcx. instance_mir ( instance. def ) ;
178178
179- let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
180- debug ! ( "fn_abi: {:?}" , fn_abi) ;
181-
182- if tcx. features ( ) . ergonomic_clones ( ) {
183- let monomorphized_mir = instance. instantiate_mir_and_normalize_erasing_regions (
179+ mir = {
180+ let mut mir = instance. instantiate_mir_and_normalize_erasing_regions (
184181 tcx,
185182 ty:: TypingEnv :: fully_monomorphized ( ) ,
186183 ty:: EarlyBinder :: bind ( mir. clone ( ) ) ,
187184 ) ;
188- mir = tcx. arena . alloc ( optimize_use_clone :: < Bx > ( cx, monomorphized_mir) ) ;
189- }
185+
186+ if tcx. features ( ) . ergonomic_clones ( ) {
187+ mir = optimize_use_clone :: < Bx > ( cx, mir) ;
188+ }
189+ mir = optimize_noop_cleanup :: < Bx > ( cx, mir, instance) ;
190+ tcx. arena . alloc ( mir)
191+ } ;
192+
193+ let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
194+ debug ! ( "fn_abi: {:?}" , fn_abi) ;
190195
191196 let debug_context = cx. create_function_debug_context ( instance, fn_abi, llfn, & mir) ;
192197
193198 let start_llbb = Bx :: append_block ( cx, llfn, "start" ) ;
194199 let mut start_bx = Bx :: build ( cx, start_llbb) ;
195200
196- if mir. basic_blocks . iter ( ) . any ( |bb | {
201+ if mir:: traversal :: mono_reachable ( & mir , tcx , instance ) . any ( |( _ , bb ) | {
197202 bb. is_cleanup || matches ! ( bb. terminator( ) . unwind( ) , Some ( mir:: UnwindAction :: Terminate ( _) ) )
198203 } ) {
199204 start_bx. set_personality_fn ( cx. eh_personality ( ) ) ;
@@ -371,6 +376,116 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
371376 mir
372377}
373378
379+ // FIXME: Move this function to mir::transform when post-mono MIR passes land.
380+ //
381+ /// Detect cases where monomorphized MIR has a cleanup block (or series of blocks) that never does
382+ /// anything, just resumes unwinding.
383+ ///
384+ /// This usually results from pre-mono MIR having a no-op drop(...) for a specific type.
385+ fn optimize_noop_cleanup < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
386+ cx : & ' a Bx :: CodegenCx ,
387+ mut mir : Body < ' tcx > ,
388+ instance : Instance < ' tcx > ,
389+ ) -> Body < ' tcx > {
390+ let tcx = cx. tcx ( ) ;
391+
392+ let mut any_action = DenseBitSet :: new_empty ( mir. basic_blocks . len ( ) ) ;
393+ for ( bb, block) in mir. basic_blocks . iter_enumerated ( ) {
394+ if !block. is_cleanup {
395+ // We don't care about non-cleanup blocks.
396+ any_action. insert ( bb) ;
397+ continue ;
398+ }
399+
400+ let mut has_actions = false ;
401+ for stmt in & block. statements {
402+ match stmt. kind {
403+ mir:: StatementKind :: SetDiscriminant { .. }
404+ | mir:: StatementKind :: Deinit ( ..)
405+ | mir:: StatementKind :: StorageLive ( ..)
406+ | mir:: StatementKind :: StorageDead ( ..)
407+ | mir:: StatementKind :: Retag ( ..)
408+ | mir:: StatementKind :: Coverage ( ..)
409+ | mir:: StatementKind :: Intrinsic ( ..)
410+ | mir:: StatementKind :: Assign ( ..) => {
411+ has_actions = true ;
412+ break ;
413+ }
414+ mir:: StatementKind :: FakeRead ( ..)
415+ | mir:: StatementKind :: PlaceMention ( ..)
416+ | mir:: StatementKind :: AscribeUserType ( ..)
417+ | mir:: StatementKind :: ConstEvalCounter
418+ | mir:: StatementKind :: Nop
419+ | mir:: StatementKind :: BackwardIncompatibleDropHint { .. } => { }
420+ }
421+ }
422+ match block. terminator ( ) . kind {
423+ mir:: TerminatorKind :: Goto { .. }
424+ | mir:: TerminatorKind :: SwitchInt { .. }
425+ | mir:: TerminatorKind :: UnwindResume
426+ | mir:: TerminatorKind :: Unreachable => { }
427+
428+ mir:: TerminatorKind :: Call { .. }
429+ | mir:: TerminatorKind :: Assert { .. }
430+ | mir:: TerminatorKind :: Yield { .. }
431+ | mir:: TerminatorKind :: InlineAsm { .. }
432+ | mir:: TerminatorKind :: CoroutineDrop
433+ | mir:: TerminatorKind :: TailCall { .. }
434+ | mir:: TerminatorKind :: UnwindTerminate ( ..)
435+ | mir:: TerminatorKind :: Return => has_actions = true ,
436+
437+ mir:: TerminatorKind :: Drop { place, .. } => {
438+ let ty = place. ty ( & mir, tcx) . ty ;
439+ debug ! ( "monomorphize: instance={:?}" , instance) ;
440+ let ty = instance. instantiate_mir_and_normalize_erasing_regions (
441+ tcx,
442+ cx. typing_env ( ) ,
443+ ty:: EarlyBinder :: bind ( ty) ,
444+ ) ;
445+ let drop_fn = Instance :: resolve_drop_in_place ( tcx, ty) ;
446+ if let ty:: InstanceKind :: DropGlue ( _, None ) = drop_fn. def {
447+ // no need to drop anything
448+ } else {
449+ has_actions = true ;
450+ }
451+ }
452+
453+ mir:: TerminatorKind :: FalseEdge { .. } | mir:: TerminatorKind :: FalseUnwind { .. } => {
454+ bug ! ( "not present in optimized mir" )
455+ }
456+ }
457+
458+ if has_actions {
459+ any_action. insert ( bb) ;
460+ }
461+ }
462+
463+ let mut to_replace = vec ! [ ] ;
464+ for ( bb, block) in mir. basic_blocks . iter_enumerated ( ) {
465+ if let Some ( mir:: UnwindAction :: Cleanup ( target) ) = block. terminator ( ) . unwind ( ) {
466+ let mut stack = vec ! [ * target] ;
467+ let mut found_action = false ;
468+ while let Some ( next) = stack. pop ( ) {
469+ if any_action. contains ( next) {
470+ found_action = true ;
471+ break ;
472+ }
473+ stack. extend ( mir. basic_blocks [ next] . terminator ( ) . successors ( ) ) ;
474+ }
475+ if !found_action {
476+ to_replace. push ( bb) ;
477+ }
478+ }
479+ }
480+
481+ for bb in to_replace {
482+ * mir. basic_blocks_mut ( ) [ bb] . terminator_mut ( ) . unwind_mut ( ) . unwrap ( ) =
483+ mir:: UnwindAction :: Continue ;
484+ }
485+
486+ mir
487+ }
488+
374489/// Produces, for each argument, a `Value` pointing at the
375490/// argument's value. As arguments are places, these are always
376491/// indirect.
0 commit comments