]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_rvalue.rs
Rollup merge of #61398 - kennytm:stabilize-copy-within, r=SimonSapin
[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, 'tcx> Builder<'a, '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, |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().lifetimes.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::Pointer { cast, source } => {
154                 let source = unpack!(block = this.as_operand(block, scope, source));
155                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
156             }
157             ExprKind::Array { fields } => {
158                 // (*) We would (maybe) be closer to codegen if we
159                 // handled this and other aggregate cases via
160                 // `into()`, not `as_rvalue` -- in that case, instead
161                 // of generating
162                 //
163                 //     let tmp1 = ...1;
164                 //     let tmp2 = ...2;
165                 //     dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
166                 //
167                 // we could just generate
168                 //
169                 //     dest.f = ...1;
170                 //     dest.g = ...2;
171                 //
172                 // The problem is that then we would need to:
173                 //
174                 // (a) have a more complex mechanism for handling
175                 //     partial cleanup;
176                 // (b) distinguish the case where the type `Foo` has a
177                 //     destructor, in which case creating an instance
178                 //     as a whole "arms" the destructor, and you can't
179                 //     write individual fields; and,
180                 // (c) handle the case where the type Foo has no
181                 //     fields. We don't want `let x: ();` to compile
182                 //     to the same MIR as `let x = ();`.
183
184                 // first process the set of fields
185                 let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
186                 let fields: Vec<_> = fields
187                     .into_iter()
188                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
189                     .collect();
190
191                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
192             }
193             ExprKind::Tuple { fields } => {
194                 // see (*) above
195                 // first process the set of fields
196                 let fields: Vec<_> = fields
197                     .into_iter()
198                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
199                     .collect();
200
201                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
202             }
203             ExprKind::Closure {
204                 closure_id,
205                 substs,
206                 upvars,
207                 movability,
208             } => {
209                 // see (*) above
210                 let operands: Vec<_> = upvars
211                     .into_iter()
212                     .map(|upvar| {
213                         let upvar = this.hir.mirror(upvar);
214                         match Category::of(&upvar.kind) {
215                             // Use as_place to avoid creating a temporary when
216                             // moving a variable into a closure, so that
217                             // borrowck knows which variables to mark as being
218                             // used as mut. This is OK here because the upvar
219                             // expressions have no side effects and act on
220                             // disjoint places.
221                             // This occurs when capturing by copy/move, while
222                             // by reference captures use as_operand
223                             Some(Category::Place) => {
224                                 let place = unpack!(block = this.as_place(block, upvar));
225                                 this.consume_by_copy_or_move(place)
226                             }
227                             _ => {
228                                 // Turn mutable borrow captures into unique
229                                 // borrow captures when capturing an immutable
230                                 // variable. This is sound because the mutation
231                                 // that caused the capture will cause an error.
232                                 match upvar.kind {
233                                     ExprKind::Borrow {
234                                         borrow_kind:
235                                             BorrowKind::Mut {
236                                                 allow_two_phase_borrow: false,
237                                             },
238                                         arg,
239                                     } => unpack!(
240                                         block = this.limit_capture_mutability(
241                                             upvar.span, upvar.ty, scope, block, arg,
242                                         )
243                                     ),
244                                     _ => unpack!(block = this.as_operand(block, scope, upvar)),
245                                 }
246                             }
247                         }
248                     }).collect();
249                 let result = match substs {
250                     UpvarSubsts::Generator(substs) => {
251                         // We implicitly set the discriminant to 0. See
252                         // librustc_mir/transform/deaggregator.rs for details.
253                         let movability = movability.unwrap();
254                         box AggregateKind::Generator(closure_id, substs, movability)
255                     }
256                     UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
257                 };
258                 block.and(Rvalue::Aggregate(result, operands))
259             }
260             ExprKind::Adt {
261                 adt_def,
262                 variant_index,
263                 substs,
264                 user_ty,
265                 fields,
266                 base,
267             } => {
268                 // see (*) above
269                 let is_union = adt_def.is_union();
270                 let active_field_index = if is_union {
271                     Some(fields[0].name.index())
272                 } else {
273                     None
274                 };
275
276                 // first process the set of fields that were provided
277                 // (evaluating them in order given by user)
278                 let fields_map: FxHashMap<_, _> = fields
279                     .into_iter()
280                     .map(|f| {
281                         (
282                             f.name,
283                             unpack!(block = this.as_operand(block, scope, f.expr)),
284                         )
285                     }).collect();
286
287                 let field_names = this.hir.all_fields(adt_def, variant_index);
288
289                 let fields = if let Some(FruInfo { base, field_types }) = base {
290                     let base = unpack!(block = this.as_place(block, base));
291
292                     // MIR does not natively support FRU, so for each
293                     // base-supplied field, generate an operand that
294                     // reads it from the base.
295                     field_names
296                         .into_iter()
297                         .zip(field_types.into_iter())
298                         .map(|(n, ty)| match fields_map.get(&n) {
299                             Some(v) => v.clone(),
300                             None => this.consume_by_copy_or_move(base.clone().field(n, ty)),
301                         }).collect()
302                 } else {
303                     field_names
304                         .iter()
305                         .filter_map(|n| fields_map.get(n).cloned())
306                         .collect()
307                 };
308
309                 let inferred_ty = expr.ty;
310                 let user_ty = user_ty.map(|ty| {
311                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
312                         span: source_info.span,
313                         user_ty: ty,
314                         inferred_ty,
315                     })
316                 });
317                 let adt = box AggregateKind::Adt(
318                     adt_def,
319                     variant_index,
320                     substs,
321                     user_ty,
322                     active_field_index,
323                 );
324                 block.and(Rvalue::Aggregate(adt, fields))
325             }
326             ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
327                 block = unpack!(this.stmt_expr(block, expr, None));
328                 block.and(this.unit_rvalue())
329             }
330             ExprKind::Yield { value } => {
331                 let value = unpack!(block = this.as_operand(block, scope, value));
332                 let resume = this.cfg.start_new_block();
333                 let cleanup = this.generator_drop_cleanup();
334                 this.cfg.terminate(
335                     block,
336                     source_info,
337                     TerminatorKind::Yield {
338                         value: value,
339                         resume: resume,
340                         drop: cleanup,
341                     },
342                 );
343                 resume.and(this.unit_rvalue())
344             }
345             ExprKind::Literal { .. }
346             | ExprKind::Block { .. }
347             | ExprKind::Match { .. }
348             | ExprKind::NeverToAny { .. }
349             | ExprKind::Use { .. }
350             | ExprKind::Loop { .. }
351             | ExprKind::LogicalOp { .. }
352             | ExprKind::Call { .. }
353             | ExprKind::Field { .. }
354             | ExprKind::Deref { .. }
355             | ExprKind::Index { .. }
356             | ExprKind::VarRef { .. }
357             | ExprKind::SelfRef
358             | ExprKind::Break { .. }
359             | ExprKind::Continue { .. }
360             | ExprKind::Return { .. }
361             | ExprKind::InlineAsm { .. }
362             | ExprKind::StaticRef { .. }
363             | ExprKind::PlaceTypeAscription { .. }
364             | ExprKind::ValueTypeAscription { .. } => {
365                 // these do not have corresponding `Rvalue` variants,
366                 // so make an operand and then return that
367                 debug_assert!(match Category::of(&expr.kind) {
368                     Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
369                     _ => true,
370                 });
371                 let operand = unpack!(block = this.as_operand(block, scope, expr));
372                 block.and(Rvalue::Use(operand))
373             }
374         }
375     }
376
377     pub fn build_binary_op(
378         &mut self,
379         mut block: BasicBlock,
380         op: BinOp,
381         span: Span,
382         ty: Ty<'tcx>,
383         lhs: Operand<'tcx>,
384         rhs: Operand<'tcx>,
385     ) -> BlockAnd<Rvalue<'tcx>> {
386         let source_info = self.source_info(span);
387         let bool_ty = self.hir.bool_ty();
388         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
389             let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
390             let result_value = self.temp(result_tup, span);
391
392             self.cfg.push_assign(
393                 block,
394                 source_info,
395                 &result_value,
396                 Rvalue::CheckedBinaryOp(op, lhs, rhs),
397             );
398             let val_fld = Field::new(0);
399             let of_fld = Field::new(1);
400
401             let val = result_value.clone().field(val_fld, ty);
402             let of = result_value.field(of_fld, bool_ty);
403
404             let err = InterpError::Overflow(op);
405
406             block = self.assert(block, Operand::Move(of), false, err, span);
407
408             block.and(Rvalue::Use(Operand::Move(val)))
409         } else {
410             if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
411                 // Checking division and remainder is more complex, since we 1. always check
412                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
413
414                 let (zero_err, overflow_err) = if op == BinOp::Div {
415                     (InterpError::DivisionByZero, InterpError::Overflow(op))
416                 } else {
417                     (InterpError::RemainderByZero, InterpError::Overflow(op))
418                 };
419
420                 // Check for / 0
421                 let is_zero = self.temp(bool_ty, span);
422                 let zero = self.zero_literal(span, ty);
423                 self.cfg.push_assign(
424                     block,
425                     source_info,
426                     &is_zero,
427                     Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
428                 );
429
430                 block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
431
432                 // We only need to check for the overflow in one case:
433                 // MIN / -1, and only for signed values.
434                 if ty.is_signed() {
435                     let neg_1 = self.neg_1_literal(span, ty);
436                     let min = self.minval_literal(span, ty);
437
438                     let is_neg_1 = self.temp(bool_ty, span);
439                     let is_min = self.temp(bool_ty, span);
440                     let of = self.temp(bool_ty, span);
441
442                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
443
444                     self.cfg.push_assign(
445                         block,
446                         source_info,
447                         &is_neg_1,
448                         Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
449                     );
450                     self.cfg.push_assign(
451                         block,
452                         source_info,
453                         &is_min,
454                         Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
455                     );
456
457                     let is_neg_1 = Operand::Move(is_neg_1);
458                     let is_min = Operand::Move(is_min);
459                     self.cfg.push_assign(
460                         block,
461                         source_info,
462                         &of,
463                         Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
464                     );
465
466                     block = self.assert(block, Operand::Move(of), false, overflow_err, span);
467                 }
468             }
469
470             block.and(Rvalue::BinaryOp(op, lhs, rhs))
471         }
472     }
473
474     fn limit_capture_mutability(
475         &mut self,
476         upvar_span: Span,
477         upvar_ty: Ty<'tcx>,
478         temp_lifetime: Option<region::Scope>,
479         mut block: BasicBlock,
480         arg: ExprRef<'tcx>,
481     ) -> BlockAnd<Operand<'tcx>> {
482         let this = self;
483
484         let source_info = this.source_info(upvar_span);
485         let temp = this
486             .local_decls
487             .push(LocalDecl::new_temp(upvar_ty, upvar_span));
488
489         this.cfg.push(
490             block,
491             Statement {
492                 source_info,
493                 kind: StatementKind::StorageLive(temp),
494             },
495         );
496
497         let arg_place = unpack!(block = this.as_place(block, arg));
498
499         let mutability = match arg_place {
500             Place::Base(PlaceBase::Local(local)) => this.local_decls[local].mutability,
501             Place::Projection(box Projection {
502                 base: Place::Base(PlaceBase::Local(local)),
503                 elem: ProjectionElem::Deref,
504             }) => {
505                 debug_assert!(
506                     this.local_decls[local].is_ref_for_guard(),
507                     "Unexpected capture place",
508                 );
509                 this.local_decls[local].mutability
510             }
511             Place::Projection(box Projection {
512                 ref base,
513                 elem: ProjectionElem::Field(upvar_index, _),
514             })
515             | Place::Projection(box Projection {
516                 base:
517                     Place::Projection(box Projection {
518                         ref base,
519                         elem: ProjectionElem::Field(upvar_index, _),
520                     }),
521                 elem: ProjectionElem::Deref,
522             }) => {
523                 // Not projected from the implicit `self` in a closure.
524                 debug_assert!(
525                     match base.local_or_deref_local() {
526                         Some(local) => local == Local::new(1),
527                         None => false,
528                     },
529                     "Unexpected capture place"
530                 );
531                 // Not in a closure
532                 debug_assert!(
533                     this.upvar_mutbls.len() > upvar_index.index(),
534                     "Unexpected capture place"
535                 );
536                 this.upvar_mutbls[upvar_index.index()]
537             }
538             _ => bug!("Unexpected capture place"),
539         };
540
541         let borrow_kind = match mutability {
542             Mutability::Not => BorrowKind::Unique,
543             Mutability::Mut => BorrowKind::Mut {
544                 allow_two_phase_borrow: false,
545             },
546         };
547
548         this.cfg.push_assign(
549             block,
550             source_info,
551             &Place::Base(PlaceBase::Local(temp)),
552             Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
553         );
554
555         // In constants, temp_lifetime is None. We should not need to drop
556         // anything because no values with a destructor can be created in
557         // a constant at this time, even if the type may need dropping.
558         if let Some(temp_lifetime) = temp_lifetime {
559             this.schedule_drop_storage_and_value(
560                 upvar_span,
561                 temp_lifetime,
562                 &Place::Base(PlaceBase::Local(temp)),
563                 upvar_ty,
564             );
565         }
566
567         block.and(Operand::Move(Place::Base(PlaceBase::Local(temp))))
568     }
569
570     // Helper to get a `-1` value of the appropriate type
571     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
572         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
573         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
574         let n = (!0u128) >> (128 - bits);
575         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
576
577         self.literal_operand(span, ty, literal)
578     }
579
580     // Helper to get the minimum value of the appropriate type
581     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
582         assert!(ty.is_signed());
583         let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
584         let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
585         let n = 1 << (bits - 1);
586         let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
587
588         self.literal_operand(span, ty, literal)
589     }
590 }