]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | //! See docs in build/expr/mod.rs |
2 | ||
9fa01778 XL |
3 | use crate::build::{BlockAnd, BlockAndExtension, Builder}; |
4 | use crate::hair::*; | |
ea8adc8c | 5 | use rustc::middle::region; |
c30ab7b3 | 6 | use rustc::mir::*; |
e9174d1e | 7 | |
a7813a04 | 8 | impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { |
e9174d1e SL |
9 | /// Compile `expr` into a fresh temporary. This is used when building |
10 | /// up rvalues so as to freeze the value that will be consumed. | |
b7449926 XL |
11 | pub fn as_temp<M>( |
12 | &mut self, | |
13 | block: BasicBlock, | |
14 | temp_lifetime: Option<region::Scope>, | |
15 | expr: M, | |
16 | mutability: Mutability, | |
17 | ) -> BlockAnd<Local> | |
18 | where | |
19 | M: Mirror<'tcx, Output = Expr<'tcx>>, | |
e9174d1e SL |
20 | { |
21 | let expr = self.hir.mirror(expr); | |
b7449926 | 22 | self.expr_as_temp(block, temp_lifetime, expr, mutability) |
e9174d1e SL |
23 | } |
24 | ||
b7449926 XL |
25 | fn expr_as_temp( |
26 | &mut self, | |
27 | mut block: BasicBlock, | |
28 | temp_lifetime: Option<region::Scope>, | |
29 | expr: Expr<'tcx>, | |
30 | mutability: Mutability, | |
31 | ) -> BlockAnd<Local> { | |
32 | debug!( | |
33 | "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", | |
34 | block, temp_lifetime, expr, mutability | |
35 | ); | |
e9174d1e SL |
36 | let this = self; |
37 | ||
041b39d2 XL |
38 | let expr_span = expr.span; |
39 | let source_info = this.source_info(expr_span); | |
b7449926 XL |
40 | if let ExprKind::Scope { |
41 | region_scope, | |
42 | lint_level, | |
43 | value, | |
44 | } = expr.kind | |
45 | { | |
ea8adc8c | 46 | return this.in_scope((region_scope, source_info), lint_level, block, |this| { |
b7449926 | 47 | this.as_temp(block, temp_lifetime, value, mutability) |
cc61c64b | 48 | }); |
e9174d1e SL |
49 | } |
50 | ||
ea8adc8c | 51 | let expr_ty = expr.ty; |
0bf4aa26 XL |
52 | let temp = { |
53 | let mut local_decl = LocalDecl::new_temp(expr_ty, expr_span); | |
54 | if mutability == Mutability::Not { | |
55 | local_decl = local_decl.immutable(); | |
56 | } | |
57 | ||
58 | debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); | |
59 | // Find out whether this temp is being created within the | |
60 | // tail expression of a block whose result is ignored. | |
a1dfa0c6 XL |
61 | if let Some(tail_info) = this.block_context.currently_in_block_tail() { |
62 | local_decl = local_decl.block_tail(tail_info); | |
0bf4aa26 | 63 | } |
0bf4aa26 XL |
64 | this.local_decls.push(local_decl) |
65 | }; | |
ea8adc8c | 66 | if !expr_ty.is_never() { |
b7449926 XL |
67 | this.cfg.push( |
68 | block, | |
69 | Statement { | |
70 | source_info, | |
71 | kind: StatementKind::StorageLive(temp), | |
72 | }, | |
73 | ); | |
5bcae85e | 74 | } |
e9174d1e | 75 | |
8faf50e0 | 76 | unpack!(block = this.into(&Place::Local(temp), block, expr)); |
e9174d1e | 77 | |
a1dfa0c6 XL |
78 | // In constants, temp_lifetime is None for temporaries that live for the |
79 | // 'static lifetime. Thus we do not drop these temporaries and simply leak them. | |
80 | // This is equivalent to what `let x = &foo();` does in functions. The temporary | |
81 | // is lifted to their surrounding scope. In a function that means the temporary lives | |
82 | // until just before the function returns. In constants that means it outlives the | |
83 | // constant's initialization value computation. Anything outliving a constant | |
84 | // must have the `'static` lifetime and live forever. | |
85 | // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything | |
86 | // within a block will keep the regular drops just like runtime code. | |
a7813a04 | 87 | if let Some(temp_lifetime) = temp_lifetime { |
8faf50e0 | 88 | this.schedule_drop_storage_and_value( |
b7449926 XL |
89 | expr_span, |
90 | temp_lifetime, | |
91 | &Place::Local(temp), | |
92 | expr_ty, | |
8faf50e0 | 93 | ); |
a7813a04 XL |
94 | } |
95 | ||
e9174d1e SL |
96 | block.and(temp) |
97 | } | |
98 | } |