]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir_build/build/expr/as_temp.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_mir_build / build / expr / as_temp.rs
CommitLineData
e9174d1e
SL
1//! See docs in build/expr/mod.rs
2
dc9dc135 3use crate::build::scope::DropKind;
dfeec247 4use crate::build::{BlockAnd, BlockAndExtension, Builder};
3dfed10e 5use crate::thir::*;
f9f354fc
XL
6use rustc_data_structures::stack::ensure_sufficient_stack;
7use rustc_hir as hir;
ba9703b0
XL
8use rustc_middle::middle::region;
9use rustc_middle::mir::*;
e9174d1e 10
dc9dc135 11impl<'a, 'tcx> Builder<'a, 'tcx> {
e9174d1e
SL
12 /// Compile `expr` into a fresh temporary. This is used when building
13 /// up rvalues so as to freeze the value that will be consumed.
dfeec247 14 crate fn as_temp<M>(
b7449926
XL
15 &mut self,
16 block: BasicBlock,
17 temp_lifetime: Option<region::Scope>,
18 expr: M,
19 mutability: Mutability,
20 ) -> BlockAnd<Local>
21 where
22 M: Mirror<'tcx, Output = Expr<'tcx>>,
e9174d1e
SL
23 {
24 let expr = self.hir.mirror(expr);
f9f354fc
XL
25 //
26 // this is the only place in mir building that we need to truly need to worry about
27 // infinite recursion. Everything else does recurse, too, but it always gets broken up
28 // at some point by inserting an intermediate temporary
29 ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability))
e9174d1e
SL
30 }
31
b7449926
XL
32 fn expr_as_temp(
33 &mut self,
34 mut block: BasicBlock,
35 temp_lifetime: Option<region::Scope>,
36 expr: Expr<'tcx>,
37 mutability: Mutability,
38 ) -> BlockAnd<Local> {
39 debug!(
40 "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
41 block, temp_lifetime, expr, mutability
42 );
e9174d1e
SL
43 let this = self;
44
041b39d2
XL
45 let expr_span = expr.span;
46 let source_info = this.source_info(expr_span);
dfeec247 47 if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
dc9dc135 48 return this.in_scope((region_scope, source_info), lint_level, |this| {
b7449926 49 this.as_temp(block, temp_lifetime, value, mutability)
cc61c64b 50 });
e9174d1e
SL
51 }
52
ea8adc8c 53 let expr_ty = expr.ty;
0bf4aa26 54 let temp = {
f9f354fc 55 let mut local_decl = LocalDecl::new(expr_ty, expr_span);
0bf4aa26
XL
56 if mutability == Mutability::Not {
57 local_decl = local_decl.immutable();
58 }
59
60 debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
61 // Find out whether this temp is being created within the
62 // tail expression of a block whose result is ignored.
a1dfa0c6
XL
63 if let Some(tail_info) = this.block_context.currently_in_block_tail() {
64 local_decl = local_decl.block_tail(tail_info);
0bf4aa26 65 }
f9f354fc
XL
66 match expr.kind {
67 ExprKind::StaticRef { def_id, .. } => {
68 assert!(!this.hir.tcx().is_thread_local_static(def_id));
69 local_decl.internal = true;
3dfed10e
XL
70 local_decl.local_info =
71 Some(box LocalInfo::StaticRef { def_id, is_thread_local: false });
f9f354fc
XL
72 }
73 ExprKind::ThreadLocalRef(def_id) => {
74 assert!(this.hir.tcx().is_thread_local_static(def_id));
75 local_decl.internal = true;
3dfed10e
XL
76 local_decl.local_info =
77 Some(box LocalInfo::StaticRef { def_id, is_thread_local: true });
f9f354fc
XL
78 }
79 _ => {}
60c5eb7d 80 }
0bf4aa26
XL
81 this.local_decls.push(local_decl)
82 };
ba9703b0 83 let temp_place = Place::from(temp);
dc9dc135 84
416331ca
XL
85 match expr.kind {
86 // Don't bother with StorageLive and Dead for these temporaries,
87 // they are never assigned.
dfeec247
XL
88 ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
89 ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } }
ba9703b0 90 if expr_ty.is_never() => {}
416331ca 91 _ => {
dfeec247
XL
92 this.cfg
93 .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
416331ca
XL
94
95 // In constants, `temp_lifetime` is `None` for temporaries that
96 // live for the `'static` lifetime. Thus we do not drop these
97 // temporaries and simply leak them.
98 // This is equivalent to what `let x = &foo();` does in
99 // functions. The temporary is lifted to their surrounding
100 // scope. In a function that means the temporary lives until
101 // just before the function returns. In constants that means it
102 // outlives the constant's initialization value computation.
103 // Anything outliving a constant must have the `'static`
104 // lifetime and live forever.
105 // Anything with a shorter lifetime (e.g the `&foo()` in
106 // `bar(&foo())` or anything within a block will keep the
107 // regular drops just like runtime code.
108 if let Some(temp_lifetime) = temp_lifetime {
dfeec247 109 this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
416331ca 110 }
dc9dc135 111 }
5bcae85e 112 }
e9174d1e 113
dc9dc135 114 unpack!(block = this.into(temp_place, block, expr));
e9174d1e 115
a7813a04 116 if let Some(temp_lifetime) = temp_lifetime {
dfeec247 117 this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
a7813a04
XL
118 }
119
e9174d1e
SL
120 block.and(temp)
121 }
122}