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