]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_rvalue.rs
7289dd96edb8dcf4a733f8221984c345b7658e2a
[rust.git] / src / librustc_mir / build / expr / as_rvalue.rs
1 //! See docs in `build/expr/mod.rs`.
2
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_data_structures::indexed_vec::Idx;
5
6 use crate::build::expr::category::{Category, RvalueFunc};
7 use crate::build::{BlockAnd, BlockAndExtension, Builder};
8 use crate::hair::*;
9 use rustc::middle::region;
10 use rustc::mir::interpret::InterpError;
11 use rustc::mir::*;
12 use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
13 use syntax_pos::Span;
14
15 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
16     /// See comment on `as_local_operand`
17     pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
18     where
19         M: Mirror<'tcx, Output = Expr<'tcx>>,
20     {
21         let local_scope = self.local_scope();
22         self.as_rvalue(block, local_scope, expr)
23     }
24
25     /// Compile `expr`, yielding an rvalue.
26     pub fn as_rvalue<M>(
27         &mut self,
28         block: BasicBlock,
29         scope: Option<region::Scope>,
30         expr: M,
31     ) -> BlockAnd<Rvalue<'tcx>>
32     where
33         M: Mirror<'tcx, Output = Expr<'tcx>>,
34     {
35         let expr = self.hir.mirror(expr);
36         self.expr_as_rvalue(block, scope, expr)
37     }
38
39     fn expr_as_rvalue(
40         &mut self,
41         mut block: BasicBlock,
42         scope: Option<region::Scope>,
43         expr: Expr<'tcx>,
44     ) -> BlockAnd<Rvalue<'tcx>> {
45         debug!(
46             "expr_as_rvalue(block={:?}, scope={:?}, expr={:?})",
47             block, scope, expr
48         );
49
50         let this = self;
51         let expr_span = expr.span;
52         let source_info = this.source_info(expr_span);
53
54         match expr.kind {
55             ExprKind::Scope {
56                 region_scope,
57                 lint_level,
58                 value,
59             } => {
60                 let region_scope = (region_scope, source_info);
61                 this.in_scope(region_scope, lint_level, block, |this| {
62                     this.as_rvalue(block, scope, value)
63                 })
64             }
65             ExprKind::Repeat { value, count } => {
66                 let value_operand = unpack!(block = this.as_operand(block, scope, value));
67                 block.and(Rvalue::Repeat(value_operand, count))
68             }
69             ExprKind::Borrow {
70                 borrow_kind,
71                 arg,
72             } => {
73                 let arg_place = match borrow_kind {
74                     BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
75                     _ => unpack!(block = this.as_place(block, arg)),
76                 };
77                 block.and(Rvalue::Ref(this.hir.tcx().types.re_erased, borrow_kind, arg_place))
78             }
79             ExprKind::Binary { op, lhs, rhs } => {
80                 let lhs = unpack!(block = this.as_operand(block, scope, lhs));
81                 let rhs = unpack!(block = this.as_operand(block, scope, rhs));
82                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
83             }
84             ExprKind::Unary { op, arg } => {
85                 let arg = unpack!(block = this.as_operand(block, scope, arg));
86                 // Check for -MIN on signed integers
87                 if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
88                     let bool_ty = this.hir.bool_ty();
89
90                     let minval = this.minval_literal(expr_span, expr.ty);
91                     let is_min = this.temp(bool_ty, expr_span);
92
93                     this.cfg.push_assign(
94                         block,
95                         source_info,
96                         &is_min,
97                         Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
98                     );
99
100                     block = this.assert(
101                         block,
102                         Operand::Move(is_min),
103                         false,
104                         InterpError::OverflowNeg,
105                         expr_span,
106                     );
107                 }
108                 block.and(Rvalue::UnaryOp(op, arg))
109             }
110             ExprKind::Box { value } => {
111                 let value = this.hir.mirror(value);
112                 // The `Box<T>` temporary created here is not a part of the HIR,
113                 // and therefore is not considered during generator OIBIT
114                 // determination. See the comment about `box` at `yield_in_scope`.
115                 let result = this
116                     .local_decls
117                     .push(LocalDecl::new_internal(expr.ty, expr_span));
118                 this.cfg.push(
119                     block,
120                     Statement {
121                         source_info,
122                         kind: StatementKind::StorageLive(result),
123                     },
124                 );
125                 if let Some(scope) = scope {
126                     // schedule a shallow free of that memory, lest we unwind:
127                     this.schedule_drop_storage_and_value(
128                         expr_span,
129                         scope,
130                         &Place::Base(PlaceBase::Local(result)),
131                         value.ty,
132                     );
133                 }
134
135                 // malloc some memory of suitable type (thus far, uninitialized):
136                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
137                 this.cfg
138                     .push_assign(block, source_info, &Place::Base(PlaceBase::Local(result)), box_);
139
140                 // initialize the box contents:
141                 unpack!(
142                     block = this.into(
143                         &Place::Base(PlaceBase::Local(result)).deref(),
144                         block, value
145                     )
146                 );
147                 block.and(Rvalue::Use(Operand::Move(Place::Base(PlaceBase::Local(result)))))
148             }
149             ExprKind::Cast { source } => {
150                 let source = unpack!(block = this.as_operand(block, scope, source));
151                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
152             }
153             ExprKind::Use { source } => {
154                 let source = unpack!(block = this.as_operand(block, scope, source));
155                 block.and(Rvalue::Use(source))
156             }
157             ExprKind::ReifyFnPointer { source } => {
158                 let source = unpack!(block = this.as_operand(block, scope, source));
159                 block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
160             }
161             ExprKind::UnsafeFnPointer { source } => {
162                 let source = unpack!(block = this.as_operand(block, scope, source));
163                 block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
164             }
165             ExprKind::ClosureFnPointer { source, unsafety } => {
166                 let source = unpack!(block = this.as_operand(block, scope, source));
167                 block.and(Rvalue::Cast(CastKind::ClosureFnPointer(unsafety), source, expr.ty))
168             }
169             ExprKind::MutToConstPointer { source } => {
170                 let source = unpack!(block = this.as_operand(block, scope, source));
171                 block.and(Rvalue::Cast(CastKind::MutToConstPointer, source, expr.ty))
172             }
173             ExprKind::Unsize { source } => {
174                 let source = unpack!(block = this.as_operand(block, scope, source));
175                 block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
176             }
177             ExprKind::Array { fields } => {
178                 // (*) We would (maybe) be closer to codegen if we
179                 // handled this and other aggregate cases via
180                 // `into()`, not `as_rvalue` -- in that case, instead
181                 // of generating
182                 //
183                 //     let tmp1 = ...1;
184                 //     let tmp2 = ...2;
185                 //     dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
186                 //
187                 // we could just generate
188                 //
189                 //     dest.f = ...1;
190                 //     dest.g = ...2;
191                 //
192                 // The problem is that then we would need to:
193                 //
194                 // (a) have a more complex mechanism for handling
195                 //     partial cleanup;
196                 // (b) distinguish the case where the type `Foo` has a
197                 //     destructor, in which case creating an instance
198                 //     as a whole "arms" the destructor, and you can't
199                 //     write individual fields; and,
200                 // (c) handle the case where the type Foo has no
201                 //     fields. We don't want `let x: ();` to compile
202                 //     to the same MIR as `let x = ();`.
203
204                 // first process the set of fields
205                 let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
206                 let fields: Vec<_> = fields
207                     .into_iter()
208                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
209                     .collect();
210
211                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
212             }
213             ExprKind::Tuple { fields } => {
214                 // see (*) above
215                 // first process the set of fields
216                 let fields: Vec<_> = fields
217                     .into_iter()
218                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
219                     .collect();
220
221                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
222             }
223             ExprKind::Closure {
224                 closure_id,
225                 substs,
226                 upvars,
227                 movability,
228             } => {
229                 // see (*) above
230                 let mut operands: Vec<_> = upvars
231                     .into_iter()
232                     .map(|upvar| {
233                         let upvar = this.hir.mirror(upvar);
234                         match Category::of(&upvar.kind) {
235                             // Use as_place to avoid creating a temporary when
236                             // moving a variable into a closure, so that
237                             // borrowck knows which variables to mark as being
238                             // used as mut. This is OK here because the upvar
239                             // expressions have no side effects and act on
240                             // disjoint places.
241                             // This occurs when capturing by copy/move, while
242                             // by reference captures use as_operand
243                             Some(Category::Place) => {
244                                 let place = unpack!(block = this.as_place(block, upvar));
245                                 this.consume_by_copy_or_move(place)
246                             }
247                             _ => {
248                                 // Turn mutable borrow captures into unique
249                                 // borrow captures when capturing an immutable
250                                 // variable. This is sound because the mutation
251                                 // that caused the capture will cause an error.
252                                 match upvar.kind {
253                                     ExprKind::Borrow {
254                                         borrow_kind:
255                                             BorrowKind::Mut {
256                                                 allow_two_phase_borrow: false,
257                                             },
258                                         arg,
259                                     } => unpack!(
260                                         block = this.limit_capture_mutability(
261                                             upvar.span, upvar.ty, scope, block, arg,
262                                         )
263                                     ),
264                                     _ => unpack!(block = this.as_operand(block, scope, upvar)),
265                                 }
266                             }
267                         }
268                     }).collect();
269                 let result = match substs {
270                     UpvarSubsts::Generator(substs) => {
271                         let movability = movability.unwrap();
272                         // Add the state operand since it follows the upvars in the generator
273                         // struct. See librustc_mir/transform/generator.rs for more details.
274                         operands.push(Operand::Constant(box Constant {
275                             span: expr_span,
276                             ty: this.hir.tcx().types.u32,
277                             user_ty: None,
278                             literal: this.hir.tcx().mk_const(
279                                 ty::Const::from_bits(
280                                     this.hir.tcx(),
281                                     0,
282                                     ty::ParamEnv::empty().and(this.hir.tcx().types.u32),
283                                 ),
284                             ),
285                         }));
286                         box AggregateKind::Generator(closure_id, substs, movability)
287                     }
288                     UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
289                 };
290                 block.and(Rvalue::Aggregate(result, operands))
291             }
292             ExprKind::Adt {
293                 adt_def,
294                 variant_index,
295                 substs,
296                 user_ty,
297                 fields,
298                 base,
299             } => {
300                 // see (*) above
301                 let is_union = adt_def.is_union();
302                 let active_field_index = if is_union {
303                     Some(fields[0].name.index())
304                 } else {
305                     None
306                 };
307
308                 // first process the set of fields that were provided
309                 // (evaluating them in order given by user)
310                 let fields_map: FxHashMap<_, _> = fields
311                     .into_iter()
312                     .map(|f| {
313                         (
314                             f.name,
315                             unpack!(block = this.as_operand(block, scope, f.expr)),
316                         )
317                     }).collect();
318
319                 let field_names = this.hir.all_fields(adt_def, variant_index);
320
321                 let fields = if let Some(FruInfo { base, field_types }) = base {
322                     let base = unpack!(block = this.as_place(block, base));
323
324                     // MIR does not natively support FRU, so for each
325                     // base-supplied field, generate an operand that
326                     // reads it from the base.
327                     field_names
328                         .into_iter()
329                         .zip(field_types.into_iter())
330                         .map(|(n, ty)| match fields_map.get(&n) {
331                             Some(v) => v.clone(),
332                             None => this.consume_by_copy_or_move(base.clone().field(n, ty)),
333                         }).collect()
334                 } else {
335                     field_names
336                         .iter()
337                         .filter_map(|n| fields_map.get(n).cloned())
338                         .collect()
339                 };
340
341                 let inferred_ty = expr.ty;
342                 let user_ty = user_ty.map(|ty| {
343                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
344                         span: source_info.span,
345                         user_ty: ty,
346                         inferred_ty,
347                     })
348                 });
349                 let adt = box AggregateKind::Adt(
350                     adt_def,
351                     variant_index,
352                     substs,
353                     user_ty,
354                     active_field_index,
355                 );
356                 block.and(Rvalue::Aggregate(adt, fields))
357             }
358             ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
359                 block = unpack!(this.stmt_expr(block, expr, None));
360                 block.and(this.unit_rvalue())
361             }
362             ExprKind::Yield { value } => {
363                 let value = unpack!(block = this.as_operand(block, scope, value));
364                 let resume = this.cfg.start_new_block();
365                 let cleanup = this.generator_drop_cleanup();
366                 this.cfg.terminate(
367                     block,
368                     source_info,
369                     TerminatorKind::Yield {
370                         value: value,
371                         resume: resume,
372                         drop: cleanup,
373                     },
374                 );
375                 resume.and(this.unit_rvalue())
376             }
377             ExprKind::Literal { .. }
378             | ExprKind::Block { .. }
379             | ExprKind::Match { .. }
380             | ExprKind::If { .. }
381             | ExprKind::NeverToAny { .. }
382             | ExprKind::Loop { .. }
383             | ExprKind::LogicalOp { .. }
384             | ExprKind::Call { .. }
385             | ExprKind::Field { .. }
386             | ExprKind::Deref { .. }
387             | ExprKind::Index { .. }
388             | ExprKind::VarRef { .. }
389             | ExprKind::SelfRef
390             | ExprKind::Break { .. }
391             | ExprKind::Continue { .. }
392             | ExprKind::Return { .. }
393             | ExprKind::InlineAsm { .. }
394             | ExprKind::StaticRef { .. }
395             | ExprKind::PlaceTypeAscription { .. }
396             | ExprKind::ValueTypeAscription { .. } => {
397                 // these do not have corresponding `Rvalue` variants,
398                 // so make an operand and then return that
399                 debug_assert!(match Category::of(&expr.kind) {
400                     Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
401                     _ => true,
402                 });
403                 let operand = unpack!(block = this.as_operand(block, scope, expr));
404                 block.and(Rvalue::Use(operand))
405             }
406         }
407     }
408
409     pub fn build_binary_op(
410         &mut self,
411         mut block: BasicBlock,
412         op: BinOp,
413         span: Span,
414         ty: Ty<'tcx>,
415         lhs: Operand<'tcx>,
416         rhs: Operand<'tcx>,
417     ) -> BlockAnd<Rvalue<'tcx>> {
418         let source_info = self.source_info(span);
419         let bool_ty = self.hir.bool_ty();
420         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
421             let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
422             let result_value = self.temp(result_tup, span);
423
424             self.cfg.push_assign(
425                 block,
426                 source_info,
427                 &result_value,
428                 Rvalue::CheckedBinaryOp(op, lhs, rhs),
429             );
430             let val_fld = Field::new(0);
431             let of_fld = Field::new(1);
432
433             let val = result_value.clone().field(val_fld, ty);
434             let of = result_value.field(of_fld, bool_ty);
435
436             let err = InterpError::Overflow(op);
437
438             block = self.assert(block, Operand::Move(of), false, err, span);
439
440             block.and(Rvalue::Use(Operand::Move(val)))
441         } else {
442             if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
443                 // Checking division and remainder is more complex, since we 1. always check
444                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
445
446                 let (zero_err, overflow_err) = if op == BinOp::Div {
447                     (InterpError::DivisionByZero, InterpError::Overflow(op))
448                 } else {
449                     (InterpError::RemainderByZero, InterpError::Overflow(op))
450                 };
451
452                 // Check for / 0
453                 let is_zero = self.temp(bool_ty, span);
454                 let zero = self.zero_literal(span, ty);
455                 self.cfg.push_assign(
456                     block,
457                     source_info,
458                     &is_zero,
459                     Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
460                 );
461
462                 block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
463
464                 // We only need to check for the overflow in one case:
465                 // MIN / -1, and only for signed values.
466                 if ty.is_signed() {
467                     let neg_1 = self.neg_1_literal(span, ty);
468                     let min = self.minval_literal(span, ty);
469
470                     let is_neg_1 = self.temp(bool_ty, span);
471                     let is_min = self.temp(bool_ty, span);
472                     let of = self.temp(bool_ty, span);
473
474                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
475
476                     self.cfg.push_assign(
477                         block,
478                         source_info,
479                         &is_neg_1,
480                         Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
481                     );
482                     self.cfg.push_assign(
483                         block,
484                         source_info,
485                         &is_min,
486                         Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
487                     );
488
489                     let is_neg_1 = Operand::Move(is_neg_1);
490                     let is_min = Operand::Move(is_min);
491                     self.cfg.push_assign(
492                         block,
493                         source_info,
494                         &of,
495                         Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
496                     );
497
498                     block = self.assert(block, Operand::Move(of), false, overflow_err, span);
499                 }
500             }
501
502             block.and(Rvalue::BinaryOp(op, lhs, rhs))
503         }
504     }
505
506     fn limit_capture_mutability(
507         &mut self,
508         upvar_span: Span,
509         upvar_ty: Ty<'tcx>,
510         temp_lifetime: Option<region::Scope>,
511         mut block: BasicBlock,
512         arg: ExprRef<'tcx>,
513     ) -> BlockAnd<Operand<'tcx>> {
514         let this = self;
515
516         let source_info = this.source_info(upvar_span);
517         let temp = this
518             .local_decls
519             .push(LocalDecl::new_temp(upvar_ty, upvar_span));
520
521         this.cfg.push(
522             block,
523             Statement {
524                 source_info,
525                 kind: StatementKind::StorageLive(temp),
526             },
527         );
528
529         let arg_place = unpack!(block = this.as_place(block, arg));
530
531         let mutability = match arg_place {
532             Place::Base(PlaceBase::Local(local)) => this.local_decls[local].mutability,
533             Place::Projection(box Projection {
534                 base: Place::Base(PlaceBase::Local(local)),
535                 elem: ProjectionElem::Deref,
536             }) => {
537                 debug_assert!(
538                     if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
539                         this.local_decls[local].is_user_variable
540                     {
541                         true
542                     } else {
543                         false
544                     },
545                     "Unexpected capture place",
546                 );
547                 this.local_decls[local].mutability
548             }
549             Place::Projection(box Projection {
550                 ref base,
551                 elem: ProjectionElem::Field(upvar_index, _),
552             })
553             | Place::Projection(box Projection {
554                 base:
555                     Place::Projection(box Projection {
556                         ref base,
557                         elem: ProjectionElem::Field(upvar_index, _),
558                     }),
559                 elem: ProjectionElem::Deref,
560             }) => {
561                 // Not projected from the implicit `self` in a closure.
562                 debug_assert!(
563                     match *base {
564                         Place::Base(PlaceBase::Local(local)) => local == Local::new(1),
565                         Place::Projection(box Projection {
566                             ref base,
567                             elem: ProjectionElem::Deref,
568                         }) => *base == Place::Base(PlaceBase::Local(Local::new(1))),
569                         _ => false,
570                     },
571                     "Unexpected capture place"
572                 );
573                 // Not in a closure
574                 debug_assert!(
575                     this.upvar_decls.len() > upvar_index.index(),
576                     "Unexpected capture place"
577                 );
578                 this.upvar_decls[upvar_index.index()].mutability
579             }
580             _ => bug!("Unexpected capture place"),
581         };
582
583         let borrow_kind = match mutability {
584             Mutability::Not => BorrowKind::Unique,
585             Mutability::Mut => BorrowKind::Mut {
586                 allow_two_phase_borrow: false,
587             },
588         };
589
590         this.cfg.push_assign(
591             block,
592             source_info,
593             &Place::Base(PlaceBase::Local(temp)),
594             Rvalue::Ref(this.hir.tcx().types.re_erased, borrow_kind, arg_place),
595         );
596
597         // In constants, temp_lifetime is None. We should not need to drop
598         // anything because no values with a destructor can be created in
599         // a constant at this time, even if the type may need dropping.
600         if let Some(temp_lifetime) = temp_lifetime {
601             this.schedule_drop_storage_and_value(
602                 upvar_span,
603                 temp_lifetime,
604                 &Place::Base(PlaceBase::Local(temp)),
605                 upvar_ty,
606             );
607         }
608
609         block.and(Operand::Move(Place::Base(PlaceBase::Local(temp))))
610     }
611
612     // Helper to get a `-1` value of the appropriate type
613     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
614         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
615         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
616         let n = (!0u128) >> (128 - bits);
617         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
618
619         self.literal_operand(span, ty, literal)
620     }
621
622     // Helper to get the minimum value of the appropriate type
623     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
624         assert!(ty.is_signed());
625         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
626         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
627         let n = 1 << (bits - 1);
628         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
629
630         self.literal_operand(span, ty, literal)
631     }
632 }