]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_temp.rs
Comment style fixes
[rust.git] / src / librustc_mir / build / expr / as_temp.rs
1 //! See docs in build/expr/mod.rs
2
3 use crate::build::{BlockAnd, BlockAndExtension, Builder};
4 use crate::build::scope::{CachedBlock, DropKind};
5 use crate::hair::*;
6 use rustc::middle::region;
7 use rustc::mir::*;
8
9 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
10     /// Compile `expr` into a fresh temporary. This is used when building
11     /// up rvalues so as to freeze the value that will be consumed.
12     pub fn as_temp<M>(
13         &mut self,
14         block: BasicBlock,
15         temp_lifetime: Option<region::Scope>,
16         expr: M,
17         mutability: Mutability,
18     ) -> BlockAnd<Local>
19     where
20         M: Mirror<'tcx, Output = Expr<'tcx>>,
21     {
22         let expr = self.hir.mirror(expr);
23         self.expr_as_temp(block, temp_lifetime, expr, mutability)
24     }
25
26     fn expr_as_temp(
27         &mut self,
28         mut block: BasicBlock,
29         temp_lifetime: Option<region::Scope>,
30         expr: Expr<'tcx>,
31         mutability: Mutability,
32     ) -> BlockAnd<Local> {
33         debug!(
34             "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
35             block, temp_lifetime, expr, mutability
36         );
37         let this = self;
38
39         let expr_span = expr.span;
40         let source_info = this.source_info(expr_span);
41         if let ExprKind::Scope {
42             region_scope,
43             lint_level,
44             value,
45         } = expr.kind
46         {
47             return this.in_scope((region_scope, source_info), lint_level, |this| {
48                 this.as_temp(block, temp_lifetime, value, mutability)
49             });
50         }
51
52         let expr_ty = expr.ty;
53         let temp = {
54             let mut local_decl = LocalDecl::new_temp(expr_ty, expr_span);
55             if mutability == Mutability::Not {
56                 local_decl = local_decl.immutable();
57             }
58
59             debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
60             // Find out whether this temp is being created within the
61             // tail expression of a block whose result is ignored.
62             if let Some(tail_info) = this.block_context.currently_in_block_tail() {
63                 local_decl = local_decl.block_tail(tail_info);
64             }
65             this.local_decls.push(local_decl)
66         };
67         let temp_place = &Place::Base(PlaceBase::Local(temp));
68
69         if !expr_ty.is_never() {
70             this.cfg.push(
71                 block,
72                 Statement {
73                     source_info,
74                     kind: StatementKind::StorageLive(temp),
75                 },
76             );
77
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.
87             if let Some(temp_lifetime) = temp_lifetime {
88                 this.schedule_drop(
89                     expr_span,
90                     temp_lifetime,
91                     temp_place,
92                     expr_ty,
93                     DropKind::Storage,
94                 );
95             }
96         }
97
98         unpack!(block = this.into(temp_place, block, expr));
99
100         if let Some(temp_lifetime) = temp_lifetime {
101             this.schedule_drop(
102                 expr_span,
103                 temp_lifetime,
104                 temp_place,
105                 expr_ty,
106                 DropKind::Value {
107                     cached_block: CachedBlock::default(),
108                 },
109             );
110         }
111
112         block.and(temp)
113     }
114 }