@@ -16,6 +16,8 @@ use hair::*;
16
16
use rustc:: ty;
17
17
use rustc:: mir:: * ;
18
18
19
+ use syntax:: abi:: Abi ;
20
+
19
21
impl < ' a , ' gcx , ' tcx > Builder < ' a , ' gcx , ' tcx > {
20
22
/// Compile `expr`, storing the result into `destination`, which
21
23
/// is assumed to be uninitialized.
@@ -206,25 +208,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206
208
}
207
209
_ => false
208
210
} ;
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[ ..] ) ;
209
221
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.
214
225
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
+ }
228
254
}
229
255
230
256
// These cases don't actually need a destination
0 commit comments