@@ -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
- }
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
+ } ;
568
571
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
+ }
572
576
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 ( ) ? ;
576
580
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
@@ -603,6 +611,23 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
603
611
caller_body : & mut Body < ' tcx > ,
604
612
callsite : & CallSite < ' tcx > ,
605
613
) -> 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
+
606
631
let tcx = inliner. tcx ( ) ;
607
632
check_mir_is_available ( inliner, caller_body, callsite. callee ) ?;
608
633
@@ -611,17 +636,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
611
636
check_codegen_attributes ( inliner, callsite, callee_attrs) ?;
612
637
inliner. check_codegen_attributes_extra ( callee_attrs) ?;
613
638
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
639
let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
626
640
check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
627
641
inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
@@ -642,54 +656,73 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
642
656
return Err ( "implementation limitation -- callee body failed validation" ) ;
643
657
}
644
658
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
+ }
659
670
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
+ } ;
661
685
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) ) ;
671
688
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
+ }
690
721
}
691
722
}
692
- }
723
+ TerminatorKind :: Drop { .. } => { }
724
+ _ => bug ! ( ) ,
725
+ } ;
693
726
694
727
let old_blocks = caller_body. basic_blocks . next_index ( ) ;
695
728
inline_call ( inliner, caller_body, callsite, callee_body) ;
@@ -854,9 +887,31 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
854
887
) {
855
888
let tcx = inliner. tcx ( ) ;
856
889
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) ,
860
915
} ;
861
916
862
917
let return_block = if let Some ( block) = target {
@@ -1014,7 +1069,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
1014
1069
// the actually used items. By doing this we can entirely avoid visiting the callee!
1015
1070
// We need to reconstruct the `required_item` for the callee so that we can find and
1016
1071
// 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 ( ) ) ) ;
1018
1073
let caller_mentioned_items = caller_body. mentioned_items . as_mut ( ) . unwrap ( ) ;
1019
1074
if let Some ( idx) = caller_mentioned_items. iter ( ) . position ( |item| item. node == callee_item) {
1020
1075
// We found the callee, so remove it and add its items instead.
0 commit comments