@@ -365,30 +365,112 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
365365                    None 
366366                } ) 
367367            } 
368-             // The `write_via_move` intrinsic needs to be special-cased very early to avoid 
369-             // introducing unnecessary copies that can be hard to remove again later: 
370-             // `write_via_move(ptr, val)` becomes `*ptr = val` but without any dropping. 
368+             // Some intrinsics are handled here because they desperately want to avoid introducing 
369+             // unnecessary copies. 
371370            ExprKind :: Call  {  ty,  fun,  ref  args,  .. } 
372-                 if  let  ty:: FnDef ( def_id,  _generic_args )  = ty. kind ( ) 
371+                 if  let  ty:: FnDef ( def_id,  generic_args )  = ty. kind ( ) 
373372                    && let  Some ( intrinsic)  = this. tcx . intrinsic ( def_id) 
374-                     && intrinsic. name  ==  sym:: write_via_move =>
373+                     && matches ! ( intrinsic. name,   sym:: write_via_move | sym :: init_box_via_move )  =>
375374            { 
376375                // We still have to evaluate the callee expression as normal (but we don't care 
377376                // about its result). 
378377                let  _fun = unpack ! ( block = this. as_local_operand( block,  fun) ) ; 
379-                 // The destination must have unit type (so we don't actually have to store anything 
380-                 // into it). 
381-                 assert ! ( destination. ty( & this. local_decls,  this. tcx) . ty. is_unit( ) ) ; 
382378
383-                 // Compile this to an assignment of the argument into the destination. 
384-                 let  [ ptr,  val]  = * * args else  { 
385-                     span_bug ! ( expr_span,  "invalid write_via_move call" ) 
386-                 } ; 
387-                 let  Some ( ptr)  = unpack ! ( block = this. as_local_operand( block,  ptr) ) . place ( )  else  { 
388-                     span_bug ! ( expr_span,  "invalid write_via_move call" ) 
389-                 } ; 
390-                 let  ptr_deref = ptr. project_deeper ( & [ ProjectionElem :: Deref ] ,  this. tcx ) ; 
391-                 this. expr_into_dest ( ptr_deref,  block,  val) 
379+                 match  intrinsic. name  { 
380+                     sym:: write_via_move => { 
381+                         // `write_via_move(ptr, val)` becomes `*ptr = val` but without any dropping. 
382+ 
383+                         // The destination must have unit type (so we don't actually have to store anything 
384+                         // into it). 
385+                         assert ! ( destination. ty( & this. local_decls,  this. tcx) . ty. is_unit( ) ) ; 
386+ 
387+                         // Compile this to an assignment of the argument into the destination. 
388+                         let  [ ptr,  val]  = * * args else  { 
389+                             span_bug ! ( expr_span,  "invalid write_via_move call" ) 
390+                         } ; 
391+                         let  Some ( ptr)  = unpack ! ( block = this. as_local_operand( block,  ptr) ) . place ( ) 
392+                         else  { 
393+                             span_bug ! ( expr_span,  "invalid write_via_move call" ) 
394+                         } ; 
395+                         let  ptr_deref = ptr. project_deeper ( & [ ProjectionElem :: Deref ] ,  this. tcx ) ; 
396+                         this. expr_into_dest ( ptr_deref,  block,  val) 
397+                     } 
398+                     sym:: init_box_via_move => { 
399+                         // `write_via_move(b, val)` becomes 
400+                         // ``` 
401+                         // *transmute::<_, *mut T>(b) = val; 
402+                         // transmute::<_, Box<T>>(b) 
403+                         // ``` 
404+                         let  t = generic_args. type_at ( 0 ) ; 
405+                         let  [ b,  val]  = * * args else  { 
406+                             span_bug ! ( expr_span,  "invalid init_box_via_move call" ) 
407+                         } ; 
408+                         let  Some ( b)  = unpack ! ( block = this. as_local_operand( block,  b) ) . place ( ) 
409+                         else  { 
410+                             span_bug ! ( expr_span,  "invalid init_box_via_move call" ) 
411+                         } ; 
412+                         // Project to the pointer inside `b`. We have to keep `b` in scope to ensure 
413+                         // it gets dropped. After the first projection we can transmute which is 
414+                         // easier. 
415+                         let  ty:: Adt ( box_adt_def,  box_adt_args)  =
416+                             b. ty ( & this. local_decls ,  this. tcx ) . ty . kind ( ) 
417+                         else  { 
418+                             span_bug ! ( expr_span,  "invalid init_box_via_move call" ) 
419+                         } ; 
420+                         let  unique_field =
421+                             this. tcx . adt_def ( box_adt_def. did ( ) ) . non_enum_variant ( ) . fields 
422+                                 [ rustc_abi:: FieldIdx :: ZERO ] 
423+                                 . did ; 
424+                         let  Some ( unique_def)  =
425+                             this. tcx . type_of ( unique_field) . instantiate_identity ( ) . ty_adt_def ( ) 
426+                         else  { 
427+                             span_bug ! ( 
428+                                 this. tcx. def_span( unique_field) , 
429+                                 "expected Box to contain Unique" 
430+                             ) 
431+                         } ; 
432+                         let  unique_ty =
433+                             Ty :: new_adt ( this. tcx ,  unique_def,  this. tcx . mk_args ( & [ box_adt_args[ 0 ] ] ) ) ; 
434+                         let  b_field = b. project_deeper ( 
435+                             & [ ProjectionElem :: Field ( rustc_abi:: FieldIdx :: ZERO ,  unique_ty) ] , 
436+                             this. tcx , 
437+                         ) ; 
438+                         // `ptr` is `b` transmuted to `*mut T`. 
439+                         let  ptr_ty = Ty :: new_mut_ptr ( this. tcx ,  t) ; 
440+                         let  ptr = this. local_decls . push ( LocalDecl :: new ( ptr_ty,  expr_span) ) ; 
441+                         this. cfg . push ( 
442+                             block, 
443+                             Statement :: new ( source_info,  StatementKind :: StorageLive ( ptr) ) , 
444+                         ) ; 
445+                         // Make sure `StorageDead` gets emitted. 
446+                         this. schedule_drop_storage_and_value ( expr_span,  this. local_scope ( ) ,  ptr) ; 
447+                         this. cfg . push_assign ( 
448+                             block, 
449+                             source_info, 
450+                             Place :: from ( ptr) , 
451+                             // Needs to be a `Copy` so that `b` still gets dropped if `val` panics. 
452+                             Rvalue :: Cast ( CastKind :: Transmute ,  Operand :: Copy ( b_field) ,  ptr_ty) , 
453+                         ) ; 
454+                         // Store `val` into `ptr`. 
455+                         let  ptr_deref =
456+                             Place :: from ( ptr) . project_deeper ( & [ ProjectionElem :: Deref ] ,  this. tcx ) ; 
457+                         unpack ! ( block = this. expr_into_dest( ptr_deref,  block,  val) ) ; 
458+                         // Return `ptr` transmuted to `Box<T>`. 
459+                         this. cfg . push_assign ( 
460+                             block, 
461+                             source_info, 
462+                             destination, 
463+                             Rvalue :: Cast ( 
464+                                 CastKind :: Transmute , 
465+                                 // Move from `b` so that does not get dropped any more. 
466+                                 Operand :: Move ( b) , 
467+                                 Ty :: new_box ( this. tcx ,  t) , 
468+                             ) , 
469+                         ) ; 
470+                         block. unit ( ) 
471+                     } 
472+                     _ => rustc_middle:: bug!( ) , 
473+                 } 
392474            } 
393475            ExprKind :: Call  {  ty :  _,  fun,  ref  args,  from_hir_call,  fn_span }  => { 
394476                let  fun = unpack ! ( block = this. as_local_operand( block,  fun) ) ; 
0 commit comments