@@ -16,6 +16,8 @@ use hair::*;
1616use rustc:: ty;
1717use rustc:: mir:: * ;
1818
19+ use syntax:: abi:: Abi ;
20+
1921impl < ' a , ' gcx , ' tcx > Builder < ' a , ' gcx , ' tcx > {
2022 /// Compile `expr`, storing the result into `destination`, which
2123 /// is assumed to be uninitialized.
@@ -206,25 +208,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206208 }
207209 _ => false
208210 } ;
211+ let intrinsic = match ty. sty {
212+ ty:: TyFnDef ( def_id, _, ref f) if
213+ f. abi ( ) == Abi :: RustIntrinsic ||
214+ f. abi ( ) == Abi :: PlatformIntrinsic =>
215+ {
216+ Some ( this. hir . tcx ( ) . item_name ( def_id) . as_str ( ) )
217+ }
218+ _ => None
219+ } ;
220+ let intrinsic = intrinsic. as_ref ( ) . map ( |s| & s[ ..] ) ;
209221 let fun = unpack ! ( block = this. as_local_operand( block, fun) ) ;
210- let args: Vec < _ > =
211- args. into_iter ( )
212- . map ( |arg| unpack ! ( block = this. as_local_operand( block, arg) ) )
213- . collect ( ) ;
222+ if intrinsic == Some ( "move_val_init" ) {
223+ // `move_val_init` has "magic" semantics - the second argument is
224+ // always evaluated "directly" into the first one.
214225
215- let success = this. cfg . start_new_block ( ) ;
216- let cleanup = this. diverge_cleanup ( ) ;
217- this. cfg . terminate ( block, source_info, TerminatorKind :: Call {
218- func : fun,
219- args : args,
220- cleanup : cleanup,
221- destination : if diverges {
222- None
223- } else {
224- Some ( ( destination. clone ( ) , success) )
225- }
226- } ) ;
227- success. unit ( )
226+ let mut args = args. into_iter ( ) ;
227+ let ptr = args. next ( ) . expect ( "0 arguments to `move_val_init`" ) ;
228+ let val = args. next ( ) . expect ( "1 argument to `move_val_init`" ) ;
229+ assert ! ( args. next( ) . is_none( ) , ">2 arguments to `move_val_init`" ) ;
230+
231+ let topmost_scope = this. topmost_scope ( ) ;
232+ let ptr = unpack ! ( block = this. as_temp( block, Some ( topmost_scope) , ptr) ) ;
233+ this. into ( & ptr. deref ( ) , block, val)
234+ } else {
235+ let args: Vec < _ > =
236+ args. into_iter ( )
237+ . map ( |arg| unpack ! ( block = this. as_local_operand( block, arg) ) )
238+ . collect ( ) ;
239+
240+ let success = this. cfg . start_new_block ( ) ;
241+ let cleanup = this. diverge_cleanup ( ) ;
242+ this. cfg . terminate ( block, source_info, TerminatorKind :: Call {
243+ func : fun,
244+ args : args,
245+ cleanup : cleanup,
246+ destination : if diverges {
247+ None
248+ } else {
249+ Some ( ( destination. clone ( ) , success) )
250+ }
251+ } ) ;
252+ success. unit ( )
253+ }
228254 }
229255
230256 // These cases don't actually need a destination
0 commit comments