@@ -6,6 +6,7 @@ use std::ops::{Range, RangeFrom};
66
77use rustc_abi:: { ExternAbi , FieldIdx } ;
88use rustc_attr_data_structures:: { InlineAttr , OptimizeAttr } ;
9+ use rustc_hir:: LangItem ;
910use rustc_hir:: def:: DefKind ;
1011use rustc_hir:: def_id:: DefId ;
1112use rustc_index:: Idx ;
@@ -553,46 +554,53 @@ fn resolve_callsite<'tcx, I: Inliner<'tcx>>(
553554 let terminator = bb_data. terminator ( ) ;
554555
555556 // FIXME(explicit_tail_calls): figure out if we can inline tail calls
556- if let TerminatorKind :: Call { ref func, fn_span, .. } = terminator. kind {
557- let func_ty = func. ty ( caller_body, tcx) ;
558- if let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) {
559- if !inliner. should_inline_for_callee ( def_id) {
560- debug ! ( "not enabled" ) ;
561- return None ;
562- }
563-
564- // To resolve an instance its args have to be fully normalized.
565- let args = tcx. try_normalize_erasing_regions ( inliner. typing_env ( ) , args) . ok ( ) ?;
566- let callee =
567- Instance :: try_resolve ( tcx, inliner. typing_env ( ) , def_id, args) . ok ( ) . flatten ( ) ?;
557+ let ( def_id, args, fn_span) = match terminator. kind {
558+ TerminatorKind :: Call { ref func, fn_span, .. } => {
559+ let func_ty = func. ty ( caller_body, tcx) ;
560+ let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) else { return None } ;
561+ ( def_id, args, fn_span)
562+ }
563+ TerminatorKind :: Drop { place, .. } => {
564+ let ty = place. ty ( caller_body, tcx) . ty ;
565+ let def_id = tcx. require_lang_item ( LangItem :: DropInPlace , terminator. source_info . span ) ;
566+ let args = tcx. mk_args ( & [ ty. into ( ) ] ) ;
567+ ( def_id, args, terminator. source_info . span )
568+ }
569+ _ => return None ,
570+ } ;
568571
569- if let InstanceKind :: Virtual ( ..) | InstanceKind :: Intrinsic ( _) = callee. def {
570- return None ;
571- }
572+ if !inliner. should_inline_for_callee ( def_id) {
573+ debug ! ( "not enabled" ) ;
574+ return None ;
575+ }
572576
573- if inliner . history ( ) . contains ( & callee . def_id ( ) ) {
574- return None ;
575- }
577+ // To resolve an instance its args have to be fully normalized.
578+ let args = tcx . try_normalize_erasing_regions ( inliner . typing_env ( ) , args ) . ok ( ) ? ;
579+ let callee = Instance :: try_resolve ( tcx , inliner . typing_env ( ) , def_id , args ) . ok ( ) . flatten ( ) ? ;
576580
577- let fn_sig = tcx. fn_sig ( def_id) . instantiate ( tcx, args) ;
581+ if let InstanceKind :: Virtual ( ..) | InstanceKind :: Intrinsic ( _) = callee. def {
582+ return None ;
583+ }
578584
579- // Additionally, check that the body that we're inlining actually agrees
580- // with the ABI of the trait that the item comes from.
581- if let InstanceKind :: Item ( instance_def_id) = callee. def
582- && tcx. def_kind ( instance_def_id) == DefKind :: AssocFn
583- && let instance_fn_sig = tcx. fn_sig ( instance_def_id) . skip_binder ( )
584- && instance_fn_sig. abi ( ) != fn_sig. abi ( )
585- {
586- return None ;
587- }
585+ if inliner. history ( ) . contains ( & callee. def_id ( ) ) {
586+ return None ;
587+ }
588588
589- let source_info = SourceInfo { span : fn_span , ..terminator . source_info } ;
589+ let fn_sig = tcx . fn_sig ( def_id ) . instantiate ( tcx , args ) ;
590590
591- return Some ( CallSite { callee, fn_sig, block : bb, source_info } ) ;
592- }
591+ // Additionally, check that the body that we're inlining actually agrees
592+ // with the ABI of the trait that the item comes from.
593+ if let InstanceKind :: Item ( instance_def_id) = callee. def
594+ && tcx. def_kind ( instance_def_id) == DefKind :: AssocFn
595+ && let instance_fn_sig = tcx. fn_sig ( instance_def_id) . skip_binder ( )
596+ && instance_fn_sig. abi ( ) != fn_sig. abi ( )
597+ {
598+ return None ;
593599 }
594600
595- None
601+ let source_info = SourceInfo { span : fn_span, ..terminator. source_info } ;
602+
603+ Some ( CallSite { callee, fn_sig, block : bb, source_info } )
596604}
597605
598606/// Attempts to inline a callsite into the caller body. When successful returns basic blocks
@@ -603,6 +611,23 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
603611 caller_body : & mut Body < ' tcx > ,
604612 callsite : & CallSite < ' tcx > ,
605613) -> Result < std:: ops:: Range < BasicBlock > , & ' static str > {
614+ // Fast path to inline trivial drops.
615+ if let InstanceKind :: DropGlue ( _, None ) = callsite. callee . def {
616+ let terminator = caller_body[ callsite. block ] . terminator_mut ( ) ;
617+ let target = match terminator. kind {
618+ TerminatorKind :: Call { target, .. } => target,
619+ TerminatorKind :: Drop { target, .. } => Some ( target) ,
620+ _ => bug ! ( "unexpected terminator kind {:?}" , terminator. kind) ,
621+ } ;
622+ if let Some ( target) = target {
623+ terminator. kind = TerminatorKind :: Goto { target } ;
624+ } else {
625+ terminator. kind = TerminatorKind :: Unreachable ;
626+ }
627+ let next_block = caller_body. basic_blocks . next_index ( ) ;
628+ return Ok ( next_block..next_block) ;
629+ }
630+
606631 let tcx = inliner. tcx ( ) ;
607632 check_mir_is_available ( inliner, caller_body, callsite. callee ) ?;
608633
@@ -611,17 +636,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
611636 check_codegen_attributes ( inliner, callsite, callee_attrs) ?;
612637 inliner. check_codegen_attributes_extra ( callee_attrs) ?;
613638
614- let terminator = caller_body[ callsite. block ] . terminator . as_ref ( ) . unwrap ( ) ;
615- let TerminatorKind :: Call { args, destination, .. } = & terminator. kind else { bug ! ( ) } ;
616- let destination_ty = destination. ty ( & caller_body. local_decls , tcx) . ty ;
617- for arg in args {
618- if !arg. node . ty ( & caller_body. local_decls , tcx) . is_sized ( tcx, inliner. typing_env ( ) ) {
619- // We do not allow inlining functions with unsized params. Inlining these functions
620- // could create unsized locals, which are unsound and being phased out.
621- return Err ( "call has unsized argument" ) ;
622- }
623- }
624-
625639 let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
626640 check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
627641 inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
@@ -642,54 +656,73 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
642656 return Err ( "implementation limitation -- callee body failed validation" ) ;
643657 }
644658
645- // Check call signature compatibility.
646- // Normally, this shouldn't be required, but trait normalization failure can create a
647- // validation ICE.
648- let output_type = callee_body. return_ty ( ) ;
649- if !util:: sub_types ( tcx, inliner. typing_env ( ) , output_type, destination_ty) {
650- trace ! ( ?output_type, ?destination_ty) ;
651- return Err ( "implementation limitation -- return type mismatch" ) ;
652- }
653- if callsite. fn_sig . abi ( ) == ExternAbi :: RustCall {
654- let ( self_arg, arg_tuple) = match & args[ ..] {
655- [ arg_tuple] => ( None , arg_tuple) ,
656- [ self_arg, arg_tuple] => ( Some ( self_arg) , arg_tuple) ,
657- _ => bug ! ( "Expected `rust-call` to have 1 or 2 args" ) ,
658- } ;
659+ let terminator = caller_body[ callsite. block ] . terminator . as_ref ( ) . unwrap ( ) ;
660+ match & terminator. kind {
661+ TerminatorKind :: Call { args, destination, .. } => {
662+ let destination_ty = destination. ty ( & caller_body. local_decls , tcx) . ty ;
663+ for arg in args {
664+ if !arg. node . ty ( & caller_body. local_decls , tcx) . is_sized ( tcx, inliner. typing_env ( ) ) {
665+ // We do not allow inlining functions with unsized params. Inlining these functions
666+ // could create unsized locals, which are unsound and being phased out.
667+ return Err ( "call has unsized argument" ) ;
668+ }
669+ }
659670
660- let self_arg_ty = self_arg. map ( |self_arg| self_arg. node . ty ( & caller_body. local_decls , tcx) ) ;
671+ // Check call signature compatibility.
672+ // Normally, this shouldn't be required, but trait normalization failure can create a
673+ // validation ICE.
674+ let output_type = callee_body. return_ty ( ) ;
675+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , output_type, destination_ty) {
676+ trace ! ( ?output_type, ?destination_ty) ;
677+ return Err ( "implementation limitation -- return type mismatch" ) ;
678+ }
679+ if callsite. fn_sig . abi ( ) == ExternAbi :: RustCall {
680+ let ( self_arg, arg_tuple) = match & args[ ..] {
681+ [ arg_tuple] => ( None , arg_tuple) ,
682+ [ self_arg, arg_tuple] => ( Some ( self_arg) , arg_tuple) ,
683+ _ => bug ! ( "Expected `rust-call` to have 1 or 2 args" ) ,
684+ } ;
661685
662- let arg_tuple_ty = arg_tuple. node . ty ( & caller_body. local_decls , tcx) ;
663- let arg_tys = if callee_body. spread_arg . is_some ( ) {
664- std:: slice:: from_ref ( & arg_tuple_ty)
665- } else {
666- let ty:: Tuple ( arg_tuple_tys) = * arg_tuple_ty. kind ( ) else {
667- bug ! ( "Closure arguments are not passed as a tuple" ) ;
668- } ;
669- arg_tuple_tys. as_slice ( )
670- } ;
686+ let self_arg_ty =
687+ self_arg. map ( |self_arg| self_arg. node . ty ( & caller_body. local_decls , tcx) ) ;
671688
672- for ( arg_ty, input) in
673- self_arg_ty. into_iter ( ) . chain ( arg_tys. iter ( ) . copied ( ) ) . zip ( callee_body. args_iter ( ) )
674- {
675- let input_type = callee_body. local_decls [ input] . ty ;
676- if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
677- trace ! ( ?arg_ty, ?input_type) ;
678- debug ! ( "failed to normalize tuple argument type" ) ;
679- return Err ( "implementation limitation" ) ;
680- }
681- }
682- } else {
683- for ( arg, input) in args. iter ( ) . zip ( callee_body. args_iter ( ) ) {
684- let input_type = callee_body. local_decls [ input] . ty ;
685- let arg_ty = arg. node . ty ( & caller_body. local_decls , tcx) ;
686- if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
687- trace ! ( ?arg_ty, ?input_type) ;
688- debug ! ( "failed to normalize argument type" ) ;
689- return Err ( "implementation limitation -- arg mismatch" ) ;
689+ let arg_tuple_ty = arg_tuple. node . ty ( & caller_body. local_decls , tcx) ;
690+ let arg_tys = if callee_body. spread_arg . is_some ( ) {
691+ std:: slice:: from_ref ( & arg_tuple_ty)
692+ } else {
693+ let ty:: Tuple ( arg_tuple_tys) = * arg_tuple_ty. kind ( ) else {
694+ bug ! ( "Closure arguments are not passed as a tuple" ) ;
695+ } ;
696+ arg_tuple_tys. as_slice ( )
697+ } ;
698+
699+ for ( arg_ty, input) in self_arg_ty
700+ . into_iter ( )
701+ . chain ( arg_tys. iter ( ) . copied ( ) )
702+ . zip ( callee_body. args_iter ( ) )
703+ {
704+ let input_type = callee_body. local_decls [ input] . ty ;
705+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
706+ trace ! ( ?arg_ty, ?input_type) ;
707+ debug ! ( "failed to normalize tuple argument type" ) ;
708+ return Err ( "implementation limitation" ) ;
709+ }
710+ }
711+ } else {
712+ for ( arg, input) in args. iter ( ) . zip ( callee_body. args_iter ( ) ) {
713+ let input_type = callee_body. local_decls [ input] . ty ;
714+ let arg_ty = arg. node . ty ( & caller_body. local_decls , tcx) ;
715+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
716+ trace ! ( ?arg_ty, ?input_type) ;
717+ debug ! ( "failed to normalize argument type" ) ;
718+ return Err ( "implementation limitation -- arg mismatch" ) ;
719+ }
720+ }
690721 }
691722 }
692- }
723+ TerminatorKind :: Drop { .. } => { }
724+ _ => bug ! ( ) ,
725+ } ;
693726
694727 let old_blocks = caller_body. basic_blocks . next_index ( ) ;
695728 inline_call ( inliner, caller_body, callsite, callee_body) ;
@@ -854,9 +887,31 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
854887) {
855888 let tcx = inliner. tcx ( ) ;
856889 let terminator = caller_body[ callsite. block ] . terminator . take ( ) . unwrap ( ) ;
857- let TerminatorKind :: Call { func, args, destination, unwind, target, .. } = terminator. kind
858- else {
859- bug ! ( "unexpected terminator kind {:?}" , terminator. kind) ;
890+ let ( args, destination, unwind, target) = match terminator. kind {
891+ TerminatorKind :: Call { args, destination, unwind, target, .. } => {
892+ ( args, destination, unwind, target)
893+ }
894+ TerminatorKind :: Drop { place, unwind, target, .. } => {
895+ // `drop_in_place` takes a `*mut`, so we need to take the address to pass it.
896+ let place_ty = place. ty ( caller_body, tcx) . ty ;
897+ let place_addr_ty = Ty :: new_mut_ptr ( tcx, place_ty) ;
898+ let arg_place: Place < ' tcx > =
899+ new_call_temp ( caller_body, callsite, place_addr_ty, Some ( target) ) . into ( ) ;
900+ caller_body[ callsite. block ] . statements . push ( Statement {
901+ source_info : callsite. source_info ,
902+ kind : StatementKind :: Assign ( Box :: new ( (
903+ arg_place,
904+ Rvalue :: RawPtr ( RawPtrKind :: Mut , place) ,
905+ ) ) ) ,
906+ } ) ;
907+ let arg = Spanned { span : terminator. source_info . span , node : Operand :: Move ( arg_place) } ;
908+
909+ // Create a dummy destination place as calls have one.
910+ let destination: Place < ' tcx > =
911+ new_call_temp ( caller_body, callsite, tcx. types . unit , Some ( target) ) . into ( ) ;
912+ ( vec ! [ arg] . into_boxed_slice ( ) , destination, unwind, Some ( target) )
913+ }
914+ _ => bug ! ( "unexpected terminator kind {:?}" , terminator. kind) ,
860915 } ;
861916
862917 let return_block = if let Some ( block) = target {
@@ -1014,7 +1069,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
10141069 // the actually used items. By doing this we can entirely avoid visiting the callee!
10151070 // We need to reconstruct the `required_item` for the callee so that we can find and
10161071 // remove it.
1017- let callee_item = MentionedItem :: Fn ( func . ty ( caller_body , tcx ) ) ;
1072+ let callee_item = MentionedItem :: Fn ( callsite . callee . ty ( tcx , inliner . typing_env ( ) ) ) ;
10181073 let caller_mentioned_items = caller_body. mentioned_items . as_mut ( ) . unwrap ( ) ;
10191074 if let Some ( idx) = caller_mentioned_items. iter ( ) . position ( |item| item. node == callee_item) {
10201075 // We found the callee, so remove it and add its items instead.
0 commit comments