@@ -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- }
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+ } ;
563571
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 ( ) ? ;
572+ if !inliner . should_inline_for_callee ( def_id ) {
573+ debug ! ( "not enabled" ) ;
574+ return None ;
575+ }
568576
569- if let InstanceKind :: Virtual ( .. ) | InstanceKind :: Intrinsic ( _ ) = callee . def {
570- return None ;
571- }
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 ( ) ? ;
572580
573- if inliner. history ( ) . contains ( & callee. def_id ( ) ) {
574- return None ;
575- }
576-
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
@@ -611,17 +619,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
611619 check_codegen_attributes ( inliner, callsite, callee_attrs) ?;
612620 inliner. check_codegen_attributes_extra ( callee_attrs) ?;
613621
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-
625622 let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
626623 check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
627624 inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
@@ -642,54 +639,73 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
642639 return Err ( "implementation limitation -- callee body failed validation" ) ;
643640 }
644641
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- } ;
642+ let terminator = caller_body[ callsite. block ] . terminator . as_ref ( ) . unwrap ( ) ;
643+ match & terminator. kind {
644+ TerminatorKind :: Call { args, destination, .. } => {
645+ let destination_ty = destination. ty ( & caller_body. local_decls , tcx) . ty ;
646+ for arg in args {
647+ if !arg. node . ty ( & caller_body. local_decls , tcx) . is_sized ( tcx, inliner. typing_env ( ) ) {
648+ // We do not allow inlining functions with unsized params. Inlining these functions
649+ // could create unsized locals, which are unsound and being phased out.
650+ return Err ( "call has unsized argument" ) ;
651+ }
652+ }
653+
654+ // Check call signature compatibility.
655+ // Normally, this shouldn't be required, but trait normalization failure can create a
656+ // validation ICE.
657+ let output_type = callee_body. return_ty ( ) ;
658+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , output_type, destination_ty) {
659+ trace ! ( ?output_type, ?destination_ty) ;
660+ return Err ( "implementation limitation -- return type mismatch" ) ;
661+ }
662+ if callsite. fn_sig . abi ( ) == ExternAbi :: RustCall {
663+ let ( self_arg, arg_tuple) = match & args[ ..] {
664+ [ arg_tuple] => ( None , arg_tuple) ,
665+ [ self_arg, arg_tuple] => ( Some ( self_arg) , arg_tuple) ,
666+ _ => bug ! ( "Expected `rust-call` to have 1 or 2 args" ) ,
667+ } ;
659668
660- let self_arg_ty = self_arg. map ( |self_arg| self_arg. node . ty ( & caller_body. local_decls , tcx) ) ;
669+ let self_arg_ty =
670+ self_arg. map ( |self_arg| self_arg. node . ty ( & caller_body. local_decls , tcx) ) ;
661671
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- } ;
672+ let arg_tuple_ty = arg_tuple. node . ty ( & caller_body. local_decls , tcx) ;
673+ let arg_tys = if callee_body. spread_arg . is_some ( ) {
674+ std:: slice:: from_ref ( & arg_tuple_ty)
675+ } else {
676+ let ty:: Tuple ( arg_tuple_tys) = * arg_tuple_ty. kind ( ) else {
677+ bug ! ( "Closure arguments are not passed as a tuple" ) ;
678+ } ;
679+ arg_tuple_tys. as_slice ( )
680+ } ;
671681
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" ) ;
682+ for ( arg_ty, input) in self_arg_ty
683+ . into_iter ( )
684+ . chain ( arg_tys. iter ( ) . copied ( ) )
685+ . zip ( callee_body. args_iter ( ) )
686+ {
687+ let input_type = callee_body. local_decls [ input] . ty ;
688+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
689+ trace ! ( ?arg_ty, ?input_type) ;
690+ debug ! ( "failed to normalize tuple argument type" ) ;
691+ return Err ( "implementation limitation" ) ;
692+ }
693+ }
694+ } else {
695+ for ( arg, input) in args. iter ( ) . zip ( callee_body. args_iter ( ) ) {
696+ let input_type = callee_body. local_decls [ input] . ty ;
697+ let arg_ty = arg. node . ty ( & caller_body. local_decls , tcx) ;
698+ if !util:: sub_types ( tcx, inliner. typing_env ( ) , input_type, arg_ty) {
699+ trace ! ( ?arg_ty, ?input_type) ;
700+ debug ! ( "failed to normalize argument type" ) ;
701+ return Err ( "implementation limitation -- arg mismatch" ) ;
702+ }
703+ }
690704 }
691705 }
692- }
706+ TerminatorKind :: Drop { .. } => { }
707+ _ => bug ! ( ) ,
708+ } ;
693709
694710 let old_blocks = caller_body. basic_blocks . next_index ( ) ;
695711 inline_call ( inliner, caller_body, callsite, callee_body) ;
@@ -854,9 +870,31 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
854870) {
855871 let tcx = inliner. tcx ( ) ;
856872 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) ;
873+ let ( args, destination, unwind, target) = match terminator. kind {
874+ TerminatorKind :: Call { args, destination, unwind, target, .. } => {
875+ ( args, destination, unwind, target)
876+ }
877+ TerminatorKind :: Drop { place, unwind, target, .. } => {
878+ // `drop_in_place` takes a `*mut`, so we need to take the address to pass it.
879+ let place_ty = place. ty ( caller_body, tcx) . ty ;
880+ let place_addr_ty = Ty :: new_mut_ptr ( tcx, place_ty) ;
881+ let arg_place: Place < ' tcx > =
882+ new_call_temp ( caller_body, callsite, place_addr_ty, Some ( target) ) . into ( ) ;
883+ caller_body[ callsite. block ] . statements . push ( Statement {
884+ source_info : callsite. source_info ,
885+ kind : StatementKind :: Assign ( Box :: new ( (
886+ arg_place,
887+ Rvalue :: RawPtr ( RawPtrKind :: Mut , place) ,
888+ ) ) ) ,
889+ } ) ;
890+ let arg = Spanned { span : terminator. source_info . span , node : Operand :: Move ( arg_place) } ;
891+
892+ // Create a dummy destination place as calls have one.
893+ let destination: Place < ' tcx > =
894+ new_call_temp ( caller_body, callsite, tcx. types . unit , Some ( target) ) . into ( ) ;
895+ ( vec ! [ arg] . into_boxed_slice ( ) , destination, unwind, Some ( target) )
896+ }
897+ _ => bug ! ( "unexpected terminator kind {:?}" , terminator. kind) ,
860898 } ;
861899
862900 let return_block = if let Some ( block) = target {
@@ -1014,7 +1052,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
10141052 // the actually used items. By doing this we can entirely avoid visiting the callee!
10151053 // We need to reconstruct the `required_item` for the callee so that we can find and
10161054 // remove it.
1017- let callee_item = MentionedItem :: Fn ( func . ty ( caller_body , tcx ) ) ;
1055+ let callee_item = MentionedItem :: Fn ( callsite . callee . ty ( tcx , inliner . typing_env ( ) ) ) ;
10181056 let caller_mentioned_items = caller_body. mentioned_items . as_mut ( ) . unwrap ( ) ;
10191057 if let Some ( idx) = caller_mentioned_items. iter ( ) . position ( |item| item. node == callee_item) {
10201058 // We found the callee, so remove it and add its items instead.
0 commit comments