@@ -6,6 +6,7 @@ use std::ops::{Range, RangeFrom};
6
6
7
7
use rustc_abi:: { ExternAbi , FieldIdx } ;
8
8
use rustc_attr_data_structures:: { InlineAttr , OptimizeAttr } ;
9
+ use rustc_hir:: LangItem ;
9
10
use rustc_hir:: def:: DefKind ;
10
11
use rustc_hir:: def_id:: DefId ;
11
12
use rustc_index:: Idx ;
@@ -553,46 +554,53 @@ fn resolve_callsite<'tcx, I: Inliner<'tcx>>(
553
554
let terminator = bb_data. terminator ( ) ;
554
555
555
556
// 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
+ } ;
563
571
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
+ }
568
576
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 ( ) ? ;
572
580
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
+ }
578
584
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
+ }
588
588
589
- let source_info = SourceInfo { span : fn_span , ..terminator . source_info } ;
589
+ let fn_sig = tcx . fn_sig ( def_id ) . instantiate ( tcx , args ) ;
590
590
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 ;
593
599
}
594
600
595
- None
601
+ let source_info = SourceInfo { span : fn_span, ..terminator. source_info } ;
602
+
603
+ Some ( CallSite { callee, fn_sig, block : bb, source_info } )
596
604
}
597
605
598
606
/// 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>>(
611
619
check_codegen_attributes ( inliner, callsite, callee_attrs) ?;
612
620
inliner. check_codegen_attributes_extra ( callee_attrs) ?;
613
621
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
-
625
622
let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
626
623
check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
627
624
inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
@@ -642,54 +639,73 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
642
639
return Err ( "implementation limitation -- callee body failed validation" ) ;
643
640
}
644
641
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
+ } ;
659
668
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) ) ;
661
671
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
+ } ;
671
681
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
+ }
690
704
}
691
705
}
692
- }
706
+ TerminatorKind :: Drop { .. } => { }
707
+ _ => bug ! ( ) ,
708
+ } ;
693
709
694
710
let old_blocks = caller_body. basic_blocks . next_index ( ) ;
695
711
inline_call ( inliner, caller_body, callsite, callee_body) ;
@@ -854,9 +870,31 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
854
870
) {
855
871
let tcx = inliner. tcx ( ) ;
856
872
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) ,
860
898
} ;
861
899
862
900
let return_block = if let Some ( block) = target {
@@ -1014,7 +1052,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
1014
1052
// the actually used items. By doing this we can entirely avoid visiting the callee!
1015
1053
// We need to reconstruct the `required_item` for the callee so that we can find and
1016
1054
// 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 ( ) ) ) ;
1018
1056
let caller_mentioned_items = caller_body. mentioned_items . as_mut ( ) . unwrap ( ) ;
1019
1057
if let Some ( idx) = caller_mentioned_items. iter ( ) . position ( |item| item. node == callee_item) {
1020
1058
// We found the callee, so remove it and add its items instead.
0 commit comments