@@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem;
88use rustc_middle:: mir:: { self , AssertKind , InlineAsmMacro , SwitchTargets , UnwindTerminateReason } ;
99use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
1010use rustc_middle:: ty:: print:: { with_no_trimmed_paths, with_no_visible_paths} ;
11- use rustc_middle:: ty:: { self , Instance , List , Ty } ;
11+ use rustc_middle:: ty:: { self , Instance , Ty } ;
1212use rustc_middle:: { bug, span_bug} ;
1313use rustc_session:: config:: OptLevel ;
1414use rustc_span:: Span ;
@@ -941,37 +941,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
941941 return merging_succ;
942942 }
943943
944- let fn_abi = bx. fn_abi_of_instance ( instance, List :: empty ( ) ) ;
944+ let result_layout =
945+ self . cx . layout_of ( self . monomorphized_place_ty ( destination. as_ref ( ) ) ) ;
945946
946- let mut llargs = Vec :: with_capacity ( 1 ) ;
947- let ret_dest = self . make_return_dest (
948- bx,
949- destination,
950- & fn_abi. ret ,
951- & mut llargs,
952- Some ( intrinsic) ,
953- ) ;
954- let dest = match ret_dest {
955- _ if fn_abi. ret . is_indirect ( ) => llargs[ 0 ] ,
956- ReturnDest :: Nothing => bx. const_undef ( bx. type_ptr ( ) ) ,
957- ReturnDest :: IndirectOperand ( dst, _) | ReturnDest :: Store ( dst) => {
958- dst. val . llval
959- }
960- ReturnDest :: DirectOperand ( _) => {
961- bug ! ( "Cannot use direct operand with an intrinsic call" )
947+ let ( result, store_in_local) = if result_layout. is_zst ( ) {
948+ (
949+ PlaceRef :: new_sized ( bx. const_undef ( bx. type_ptr ( ) ) , result_layout) ,
950+ None ,
951+ )
952+ } else if let Some ( local) = destination. as_local ( ) {
953+ match self . locals [ local] {
954+ LocalRef :: Place ( dest) => ( dest, None ) ,
955+ LocalRef :: UnsizedPlace ( _) => bug ! ( "return type must be sized" ) ,
956+ LocalRef :: PendingOperand => {
957+ // Currently, intrinsics always need a location to store
958+ // the result, so we create a temporary `alloca` for the
959+ // result.
960+ let tmp = PlaceRef :: alloca ( bx, result_layout) ;
961+ tmp. storage_live ( bx) ;
962+ ( tmp, Some ( local) )
963+ }
964+ LocalRef :: Operand ( _) => {
965+ bug ! ( "place local already assigned to" ) ;
966+ }
962967 }
968+ } else {
969+ ( self . codegen_place ( bx, destination. as_ref ( ) ) , None )
963970 } ;
964971
972+ if result. val . align < result. layout . align . abi {
973+ // Currently, MIR code generation does not create calls
974+ // that store directly to fields of packed structs (in
975+ // fact, the calls it creates write only to temps).
976+ //
977+ // If someone changes that, please update this code path
978+ // to create a temporary.
979+ span_bug ! ( self . mir. span, "can't directly store to unaligned value" ) ;
980+ }
981+
965982 let args: Vec < _ > =
966983 args. iter ( ) . map ( |arg| self . codegen_operand ( bx, & arg. node ) ) . collect ( ) ;
967984
968- let result = PlaceRef :: new_sized ( dest, fn_abi. ret . layout ) ;
969-
970985 match self . codegen_intrinsic_call ( bx, instance, & args, result, source_info)
971986 {
972987 Ok ( ( ) ) => {
973- if let ReturnDest :: IndirectOperand ( dst, _) = ret_dest {
974- self . store_return ( bx, ret_dest, & fn_abi. ret , dst. val . llval ) ;
988+ if let Some ( local) = store_in_local {
989+ let op = bx. load_operand ( result) ;
990+ result. storage_dead ( bx) ;
991+ self . overwrite_local ( local, LocalRef :: Operand ( op) ) ;
992+ self . debug_introduce_local ( bx, local) ;
975993 }
976994
977995 return if let Some ( target) = target {
@@ -1026,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10261044 // We still need to call `make_return_dest` even if there's no `target`, since
10271045 // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
10281046 // and `make_return_dest` adds the return-place indirect pointer to `llargs`.
1029- let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs, None ) ;
1047+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
10301048 let destination = target. map ( |target| ( return_dest, target) ) ;
10311049
10321050 // Split the rust-call tupled arguments off.
@@ -1857,7 +1875,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
18571875 dest : mir:: Place < ' tcx > ,
18581876 fn_ret : & ArgAbi < ' tcx , Ty < ' tcx > > ,
18591877 llargs : & mut Vec < Bx :: Value > ,
1860- intrinsic : Option < ty:: IntrinsicDef > ,
18611878 ) -> ReturnDest < ' tcx , Bx :: Value > {
18621879 // If the return is ignored, we can just return a do-nothing `ReturnDest`.
18631880 if fn_ret. is_ignore ( ) {
@@ -1877,13 +1894,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
18771894 tmp. storage_live ( bx) ;
18781895 llargs. push ( tmp. val . llval ) ;
18791896 ReturnDest :: IndirectOperand ( tmp, index)
1880- } else if intrinsic. is_some ( ) {
1881- // Currently, intrinsics always need a location to store
1882- // the result, so we create a temporary `alloca` for the
1883- // result.
1884- let tmp = PlaceRef :: alloca ( bx, fn_ret. layout ) ;
1885- tmp. storage_live ( bx) ;
1886- ReturnDest :: IndirectOperand ( tmp, index)
18871897 } else {
18881898 ReturnDest :: DirectOperand ( index)
18891899 } ;
@@ -1893,7 +1903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
18931903 }
18941904 }
18951905 } else {
1896- self . codegen_place ( bx, mir :: PlaceRef { local : dest. local , projection : dest . projection } )
1906+ self . codegen_place ( bx, dest. as_ref ( ) )
18971907 } ;
18981908 if fn_ret. is_indirect ( ) {
18991909 if dest. val . align < dest. layout . align . abi {
0 commit comments