]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/rvalue.rs
typestrong constant integers
[rust.git] / src / librustc_trans / trans / mir / rvalue.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use llvm::ValueRef;
12 use rustc::middle::ty::{self, Ty};
13 use middle::ty::cast::{CastTy, IntTy};
14 use middle::const_eval::ConstVal;
15 use rustc_const_eval::ConstInt;
16 use rustc::mir::repr as mir;
17
18 use trans::asm;
19 use trans::base;
20 use trans::callee::Callee;
21 use trans::common::{self, BlockAndBuilder, Result};
22 use trans::debuginfo::DebugLoc;
23 use trans::declare;
24 use trans::expr;
25 use trans::adt;
26 use trans::machine;
27 use trans::type_::Type;
28 use trans::type_of;
29 use trans::tvec;
30 use trans::Disr;
31
32 use super::MirContext;
33 use super::operand::{OperandRef, OperandValue};
34 use super::lvalue::LvalueRef;
35
36 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
37     pub fn trans_rvalue(&mut self,
38                         bcx: BlockAndBuilder<'bcx, 'tcx>,
39                         dest: LvalueRef<'tcx>,
40                         rvalue: &mir::Rvalue<'tcx>)
41                         -> BlockAndBuilder<'bcx, 'tcx>
42     {
43         debug!("trans_rvalue(dest.llval={}, rvalue={:?})",
44                bcx.val_to_string(dest.llval),
45                rvalue);
46
47         match *rvalue {
48            mir::Rvalue::Use(ref operand) => {
49                let tr_operand = self.trans_operand(&bcx, operand);
50                // FIXME: consider not copying constants through stack. (fixable by translating
51                // constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
52                self.store_operand(&bcx, dest.llval, tr_operand);
53                self.set_operand_dropped(&bcx, operand);
54                bcx
55            }
56
57             mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => {
58                 if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
59                     // into-coerce of a thin pointer to a fat pointer - just
60                     // use the operand path.
61                     let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
62                     self.store_operand(&bcx, dest.llval, temp);
63                     return bcx;
64                 }
65
66                 // Unsize of a nontrivial struct. I would prefer for
67                 // this to be eliminated by MIR translation, but
68                 // `CoerceUnsized` can be passed by a where-clause,
69                 // so the (generic) MIR may not be able to expand it.
70                 let operand = self.trans_operand(&bcx, operand);
71                 bcx.with_block(|bcx| {
72                     match operand.val {
73                         OperandValue::FatPtr(..) => unreachable!(),
74                         OperandValue::Immediate(llval) => {
75                             // unsize from an immediate structure. We don't
76                             // really need a temporary alloca here, but
77                             // avoiding it would require us to have
78                             // `coerce_unsized_into` use extractvalue to
79                             // index into the struct, and this case isn't
80                             // important enough for it.
81                             debug!("trans_rvalue: creating ugly alloca");
82                             let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp");
83                             base::store_ty(bcx, llval, lltemp, operand.ty);
84                             base::coerce_unsized_into(bcx,
85                                                       lltemp, operand.ty,
86                                                       dest.llval, cast_ty);
87                         }
88                         OperandValue::Ref(llref) => {
89                             base::coerce_unsized_into(bcx,
90                                                       llref, operand.ty,
91                                                       dest.llval, cast_ty);
92                         }
93                     }
94                 });
95                 bcx
96             }
97
98             mir::Rvalue::Repeat(ref elem, ref count) => {
99                 let tr_elem = self.trans_operand(&bcx, elem);
100                 let count = ConstVal::Integral(ConstInt::Usize(count.value));
101                 let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
102                 let bcx = bcx.map_block(|block| {
103                     let base = expr::get_dataptr(block, dest.llval);
104                     tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
105                         self.store_operand_direct(block, llslot, tr_elem);
106                         block
107                     })
108                 });
109                 self.set_operand_dropped(&bcx, elem);
110                 bcx
111             }
112
113             mir::Rvalue::Aggregate(ref kind, ref operands) => {
114                 match *kind {
115                     mir::AggregateKind::Adt(adt_def, index, _) => {
116                         let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
117                         let disr = Disr::from(adt_def.variants[index].disr_val);
118                         bcx.with_block(|bcx| {
119                             adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr));
120                         });
121                         for (i, operand) in operands.iter().enumerate() {
122                             let op = self.trans_operand(&bcx, operand);
123                             // Do not generate stores and GEPis for zero-sized fields.
124                             if !common::type_is_zero_size(bcx.ccx(), op.ty) {
125                                 let val = adt::MaybeSizedValue::sized(dest.llval);
126                                 let lldest_i = bcx.with_block(|bcx| {
127                                     adt::trans_field_ptr(bcx, &repr, val, disr, i)
128                                 });
129                                 self.store_operand(&bcx, lldest_i, op);
130                                 self.set_operand_dropped(&bcx, operand);
131                             }
132                         }
133                     },
134                     _ => {
135                         for (i, operand) in operands.iter().enumerate() {
136                             let op = self.trans_operand(&bcx, operand);
137                             // Do not generate stores and GEPis for zero-sized fields.
138                             if !common::type_is_zero_size(bcx.ccx(), op.ty) {
139                                 // Note: perhaps this should be StructGep, but
140                                 // note that in some cases the values here will
141                                 // not be structs but arrays.
142                                 let dest = bcx.gepi(dest.llval, &[0, i]);
143                                 self.store_operand(&bcx, dest, op);
144                                 self.set_operand_dropped(&bcx, operand);
145                             }
146                         }
147                     }
148                 }
149                 bcx
150             }
151
152             mir::Rvalue::Slice { ref input, from_start, from_end } => {
153                 let ccx = bcx.ccx();
154                 let input = self.trans_lvalue(&bcx, input);
155                 let (llbase, lllen) = bcx.with_block(|bcx| {
156                     tvec::get_base_and_len(bcx,
157                                            input.llval,
158                                            input.ty.to_ty(bcx.tcx()))
159                 });
160                 let llbase1 = bcx.gepi(llbase, &[from_start]);
161                 let adj = common::C_uint(ccx, from_start + from_end);
162                 let lllen1 = bcx.sub(lllen, adj);
163                 let (lladdrdest, llmetadest) = bcx.with_block(|bcx| {
164                     (expr::get_dataptr(bcx, dest.llval), expr::get_meta(bcx, dest.llval))
165                 });
166                 bcx.store(llbase1, lladdrdest);
167                 bcx.store(lllen1, llmetadest);
168                 bcx
169             }
170
171             mir::Rvalue::InlineAsm(ref inline_asm) => {
172                 bcx.map_block(|bcx| {
173                     asm::trans_inline_asm(bcx, inline_asm)
174                 })
175             }
176
177             _ => {
178                 assert!(rvalue_creates_operand(rvalue));
179                 let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
180                 self.store_operand(&bcx, dest.llval, temp);
181                 bcx
182             }
183         }
184     }
185
186     pub fn trans_rvalue_operand(&mut self,
187                                 bcx: BlockAndBuilder<'bcx, 'tcx>,
188                                 rvalue: &mir::Rvalue<'tcx>)
189                                 -> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>)
190     {
191         assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
192
193         match *rvalue {
194             mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => {
195                 let operand = self.trans_operand(&bcx, operand);
196                 debug!("cast operand is {}", operand.repr(&bcx));
197                 let cast_ty = bcx.monomorphize(&cast_ty);
198
199                 let val = match *kind {
200                     mir::CastKind::ReifyFnPointer => {
201                         match operand.ty.sty {
202                             ty::TyFnDef(def_id, substs, _) => {
203                                 OperandValue::Immediate(
204                                     Callee::def(bcx.ccx(), def_id, substs, operand.ty)
205                                         .reify(bcx.ccx()).val)
206                             }
207                             _ => {
208                                 unreachable!("{} cannot be reified to a fn ptr", operand.ty)
209                             }
210                         }
211                     }
212                     mir::CastKind::UnsafeFnPointer => {
213                         // this is a no-op at the LLVM level
214                         operand.val
215                     }
216                     mir::CastKind::Unsize => {
217                         // unsize targets other than to a fat pointer currently
218                         // can't be operands.
219                         assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty));
220
221                         match operand.val {
222                             OperandValue::FatPtr(..) => {
223                                 // unsize from a fat pointer - this is a
224                                 // "trait-object-to-supertrait" coercion, for
225                                 // example,
226                                 //   &'a fmt::Debug+Send => &'a fmt::Debug,
227                                 // and is a no-op at the LLVM level
228                                 operand.val
229                             }
230                             OperandValue::Immediate(lldata) => {
231                                 // "standard" unsize
232                                 let (lldata, llextra) = bcx.with_block(|bcx| {
233                                     base::unsize_thin_ptr(bcx, lldata,
234                                                           operand.ty, cast_ty)
235                                 });
236                                 OperandValue::FatPtr(lldata, llextra)
237                             }
238                             OperandValue::Ref(_) => {
239                                 bcx.sess().bug(
240                                     &format!("by-ref operand {} in trans_rvalue_operand",
241                                              operand.repr(&bcx)));
242                             }
243                         }
244                     }
245                     mir::CastKind::Misc if common::type_is_immediate(bcx.ccx(), operand.ty) => {
246                         debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty));
247                         let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
248                         let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
249                         let ll_t_in = type_of::arg_type_of(bcx.ccx(), operand.ty);
250                         let ll_t_out = type_of::arg_type_of(bcx.ccx(), cast_ty);
251                         let (llval, ll_t_in, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in {
252                             let repr = adt::represent_type(bcx.ccx(), operand.ty);
253                             let llval = operand.immediate();
254                             let discr = bcx.with_block(|bcx| {
255                                 adt::trans_get_discr(bcx, &repr, llval, None, true)
256                             });
257                             (discr, common::val_ty(discr), adt::is_discr_signed(&repr))
258                         } else {
259                             (operand.immediate(), ll_t_in, operand.ty.is_signed())
260                         };
261
262                         let newval = match (r_t_in, r_t_out) {
263                             (CastTy::Int(_), CastTy::Int(_)) => {
264                                 let srcsz = ll_t_in.int_width();
265                                 let dstsz = ll_t_out.int_width();
266                                 if srcsz == dstsz {
267                                     bcx.bitcast(llval, ll_t_out)
268                                 } else if srcsz > dstsz {
269                                     bcx.trunc(llval, ll_t_out)
270                                 } else if signed {
271                                     bcx.sext(llval, ll_t_out)
272                                 } else {
273                                     bcx.zext(llval, ll_t_out)
274                                 }
275                             }
276                             (CastTy::Float, CastTy::Float) => {
277                                 let srcsz = ll_t_in.float_width();
278                                 let dstsz = ll_t_out.float_width();
279                                 if dstsz > srcsz {
280                                     bcx.fpext(llval, ll_t_out)
281                                 } else if srcsz > dstsz {
282                                     bcx.fptrunc(llval, ll_t_out)
283                                 } else {
284                                     llval
285                                 }
286                             }
287                             (CastTy::Ptr(_), CastTy::Ptr(_)) |
288                             (CastTy::FnPtr, CastTy::Ptr(_)) |
289                             (CastTy::RPtr(_), CastTy::Ptr(_)) =>
290                                 bcx.pointercast(llval, ll_t_out),
291                             (CastTy::Ptr(_), CastTy::Int(_)) |
292                             (CastTy::FnPtr, CastTy::Int(_)) =>
293                                 bcx.ptrtoint(llval, ll_t_out),
294                             (CastTy::Int(_), CastTy::Ptr(_)) =>
295                                 bcx.inttoptr(llval, ll_t_out),
296                             (CastTy::Int(_), CastTy::Float) if signed =>
297                                 bcx.sitofp(llval, ll_t_out),
298                             (CastTy::Int(_), CastTy::Float) =>
299                                 bcx.uitofp(llval, ll_t_out),
300                             (CastTy::Float, CastTy::Int(IntTy::I)) =>
301                                 bcx.fptosi(llval, ll_t_out),
302                             (CastTy::Float, CastTy::Int(_)) =>
303                                 bcx.fptoui(llval, ll_t_out),
304                             _ => bcx.ccx().sess().bug(
305                                 &format!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
306                             )
307                         };
308                         OperandValue::Immediate(newval)
309                     }
310                     mir::CastKind::Misc => { // Casts from a fat-ptr.
311                         let ll_cast_ty = type_of::arg_type_of(bcx.ccx(), cast_ty);
312                         let ll_from_ty = type_of::arg_type_of(bcx.ccx(), operand.ty);
313                         if let OperandValue::FatPtr(data_ptr, meta_ptr) = operand.val {
314                             if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
315                                 let ll_cft = ll_cast_ty.field_types();
316                                 let ll_fft = ll_from_ty.field_types();
317                                 let data_cast = bcx.pointercast(data_ptr, ll_cft[0]);
318                                 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
319                                 OperandValue::FatPtr(data_cast, meta_ptr)
320                             } else { // cast to thin-ptr
321                                 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
322                                 // pointer-cast of that pointer to desired pointer type.
323                                 let llval = bcx.pointercast(data_ptr, ll_cast_ty);
324                                 OperandValue::Immediate(llval)
325                             }
326                         } else {
327                             panic!("Unexpected non-FatPtr operand")
328                         }
329                     }
330                 };
331                 let operand = OperandRef {
332                     val: val,
333                     ty: cast_ty
334                 };
335                 (bcx, operand)
336             }
337
338             mir::Rvalue::Ref(_, bk, ref lvalue) => {
339                 let tr_lvalue = self.trans_lvalue(&bcx, lvalue);
340
341                 let ty = tr_lvalue.ty.to_ty(bcx.tcx());
342                 let ref_ty = bcx.tcx().mk_ref(
343                     bcx.tcx().mk_region(ty::ReStatic),
344                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }
345                 );
346
347                 // Note: lvalues are indirect, so storing the `llval` into the
348                 // destination effectively creates a reference.
349                 let operand = if common::type_is_sized(bcx.tcx(), ty) {
350                     OperandRef {
351                         val: OperandValue::Immediate(tr_lvalue.llval),
352                         ty: ref_ty,
353                     }
354                 } else {
355                     OperandRef {
356                         val: OperandValue::FatPtr(tr_lvalue.llval,
357                                                   tr_lvalue.llextra),
358                         ty: ref_ty,
359                     }
360                 };
361                 (bcx, operand)
362             }
363
364             mir::Rvalue::Len(ref lvalue) => {
365                 let tr_lvalue = self.trans_lvalue(&bcx, lvalue);
366                 let operand = OperandRef {
367                     val: OperandValue::Immediate(self.lvalue_len(&bcx, tr_lvalue)),
368                     ty: bcx.tcx().types.usize,
369                 };
370                 (bcx, operand)
371             }
372
373             mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
374                 let lhs = self.trans_operand(&bcx, lhs);
375                 let rhs = self.trans_operand(&bcx, rhs);
376                 let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) {
377                     match (lhs.val, rhs.val) {
378                         (OperandValue::FatPtr(lhs_addr, lhs_extra),
379                          OperandValue::FatPtr(rhs_addr, rhs_extra)) => {
380                             bcx.with_block(|bcx| {
381                                 base::compare_fat_ptrs(bcx,
382                                                        lhs_addr, lhs_extra,
383                                                        rhs_addr, rhs_extra,
384                                                        lhs.ty, op.to_hir_binop(),
385                                                        DebugLoc::None)
386                             })
387                         }
388                         _ => unreachable!()
389                     }
390
391                 } else {
392                     self.trans_scalar_binop(&bcx, op,
393                                             lhs.immediate(), rhs.immediate(),
394                                             lhs.ty)
395                 };
396                 let operand = OperandRef {
397                     val: OperandValue::Immediate(llresult),
398                     ty: self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty),
399                 };
400                 (bcx, operand)
401             }
402
403             mir::Rvalue::UnaryOp(op, ref operand) => {
404                 let operand = self.trans_operand(&bcx, operand);
405                 let lloperand = operand.immediate();
406                 let is_float = operand.ty.is_fp();
407                 let llval = match op {
408                     mir::UnOp::Not => bcx.not(lloperand),
409                     mir::UnOp::Neg => if is_float {
410                         bcx.fneg(lloperand)
411                     } else {
412                         bcx.neg(lloperand)
413                     }
414                 };
415                 (bcx, OperandRef {
416                     val: OperandValue::Immediate(llval),
417                     ty: operand.ty,
418                 })
419             }
420
421             mir::Rvalue::Box(content_ty) => {
422                 let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
423                 let llty = type_of::type_of(bcx.ccx(), content_ty);
424                 let llsize = machine::llsize_of(bcx.ccx(), llty);
425                 let align = type_of::align_of(bcx.ccx(), content_ty);
426                 let llalign = common::C_uint(bcx.ccx(), align);
427                 let llty_ptr = llty.ptr_to();
428                 let box_ty = bcx.tcx().mk_box(content_ty);
429                 let mut llval = None;
430                 let bcx = bcx.map_block(|bcx| {
431                     let Result { bcx, val } = base::malloc_raw_dyn(bcx,
432                                                                    llty_ptr,
433                                                                    box_ty,
434                                                                    llsize,
435                                                                    llalign,
436                                                                    DebugLoc::None);
437                     llval = Some(val);
438                     bcx
439                 });
440                 let operand = OperandRef {
441                     val: OperandValue::Immediate(llval.unwrap()),
442                     ty: box_ty,
443                 };
444                 (bcx, operand)
445             }
446
447             mir::Rvalue::Use(..) |
448             mir::Rvalue::Repeat(..) |
449             mir::Rvalue::Aggregate(..) |
450             mir::Rvalue::Slice { .. } |
451             mir::Rvalue::InlineAsm(..) => {
452                 bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
453             }
454         }
455     }
456
457     pub fn trans_scalar_binop(&mut self,
458                               bcx: &BlockAndBuilder<'bcx, 'tcx>,
459                               op: mir::BinOp,
460                               lhs: ValueRef,
461                               rhs: ValueRef,
462                               input_ty: Ty<'tcx>) -> ValueRef {
463         let is_float = input_ty.is_fp();
464         let is_signed = input_ty.is_signed();
465         match op {
466             mir::BinOp::Add => if is_float {
467                 bcx.fadd(lhs, rhs)
468             } else {
469                 bcx.add(lhs, rhs)
470             },
471             mir::BinOp::Sub => if is_float {
472                 bcx.fsub(lhs, rhs)
473             } else {
474                 bcx.sub(lhs, rhs)
475             },
476             mir::BinOp::Mul => if is_float {
477                 bcx.fmul(lhs, rhs)
478             } else {
479                 bcx.mul(lhs, rhs)
480             },
481             mir::BinOp::Div => if is_float {
482                 bcx.fdiv(lhs, rhs)
483             } else if is_signed {
484                 bcx.sdiv(lhs, rhs)
485             } else {
486                 bcx.udiv(lhs, rhs)
487             },
488             mir::BinOp::Rem => if is_float {
489                 // LLVM currently always lowers the `frem` instructions appropriate
490                 // library calls typically found in libm. Notably f64 gets wired up
491                 // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
492                 // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
493                 // instead just an inline function in a header that goes up to a
494                 // f64, uses `fmod`, and then comes back down to a f32.
495                 //
496                 // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
497                 // still unconditionally lower frem instructions over 32-bit floats
498                 // to a call to `fmodf`. To work around this we special case MSVC
499                 // 32-bit float rem instructions and instead do the call out to
500                 // `fmod` ourselves.
501                 //
502                 // Note that this is currently duplicated with src/libcore/ops.rs
503                 // which does the same thing, and it would be nice to perhaps unify
504                 // these two implementations one day! Also note that we call `fmod`
505                 // for both 32 and 64-bit floats because if we emit any FRem
506                 // instruction at all then LLVM is capable of optimizing it into a
507                 // 32-bit FRem (which we're trying to avoid).
508                 let tcx = bcx.tcx();
509                 let use_fmod = tcx.sess.target.target.options.is_like_msvc &&
510                     tcx.sess.target.target.arch == "x86";
511                 if use_fmod {
512                     let f64t = Type::f64(bcx.ccx());
513                     let fty = Type::func(&[f64t, f64t], &f64t);
514                     let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty,
515                                                     tcx.types.f64);
516                     if input_ty == tcx.types.f32 {
517                         let lllhs = bcx.fpext(lhs, f64t);
518                         let llrhs = bcx.fpext(rhs, f64t);
519                         let llres = bcx.call(llfn, &[lllhs, llrhs], None, None);
520                         bcx.fptrunc(llres, Type::f32(bcx.ccx()))
521                     } else {
522                         bcx.call(llfn, &[lhs, rhs], None, None)
523                     }
524                 } else {
525                     bcx.frem(lhs, rhs)
526                 }
527             } else if is_signed {
528                 bcx.srem(lhs, rhs)
529             } else {
530                 bcx.urem(lhs, rhs)
531             },
532             mir::BinOp::BitOr => bcx.or(lhs, rhs),
533             mir::BinOp::BitAnd => bcx.and(lhs, rhs),
534             mir::BinOp::BitXor => bcx.xor(lhs, rhs),
535             mir::BinOp::Shl => {
536                 bcx.with_block(|bcx| {
537                     common::build_unchecked_lshift(bcx,
538                                                    lhs,
539                                                    rhs,
540                                                    DebugLoc::None)
541                 })
542             }
543             mir::BinOp::Shr => {
544                 bcx.with_block(|bcx| {
545                     common::build_unchecked_rshift(bcx,
546                                                    input_ty,
547                                                    lhs,
548                                                    rhs,
549                                                    DebugLoc::None)
550                 })
551             }
552             mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt |
553             mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => {
554                 bcx.with_block(|bcx| {
555                     base::compare_scalar_types(bcx, lhs, rhs, input_ty,
556                                                op.to_hir_binop(), DebugLoc::None)
557                 })
558             }
559         }
560     }
561 }
562
563 pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
564     match *rvalue {
565         mir::Rvalue::Ref(..) |
566         mir::Rvalue::Len(..) |
567         mir::Rvalue::Cast(..) | // (*)
568         mir::Rvalue::BinaryOp(..) |
569         mir::Rvalue::UnaryOp(..) |
570         mir::Rvalue::Box(..) =>
571             true,
572         mir::Rvalue::Use(..) | // (**)
573         mir::Rvalue::Repeat(..) |
574         mir::Rvalue::Aggregate(..) |
575         mir::Rvalue::Slice { .. } |
576         mir::Rvalue::InlineAsm(..) =>
577             false,
578     }
579
580     // (*) this is only true if the type is suitable
581     // (**) we need to zero-out the source operand after moving, so we are restricted to either
582     // ensuring all users of `Use` zero it out themselves or not allowing to “create” operand for
583     // it.
584 }