1 //! See docs in build/expr/mod.rs
3 use crate::build
::scope
::DropKind
;
4 use crate::build
::{BlockAnd, BlockAndExtension, Builder}
;
6 use rustc_data_structures
::stack
::ensure_sufficient_stack
;
8 use rustc_middle
::middle
::region
;
9 use rustc_middle
::mir
::*;
11 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
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.
17 temp_lifetime
: Option
<region
::Scope
>,
19 mutability
: Mutability
,
22 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
24 let expr
= self.hir
.mirror(expr
);
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
))
34 mut block
: BasicBlock
,
35 temp_lifetime
: Option
<region
::Scope
>,
37 mutability
: Mutability
,
38 ) -> BlockAnd
<Local
> {
40 "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
41 block
, temp_lifetime
, expr
, mutability
45 let expr_span
= expr
.span
;
46 let source_info
= this
.source_info(expr_span
);
47 if let ExprKind
::Scope { region_scope, lint_level, value }
= expr
.kind
{
48 return this
.in_scope((region_scope
, source_info
), lint_level
, |this
| {
49 this
.as_temp(block
, temp_lifetime
, value
, mutability
)
53 let expr_ty
= expr
.ty
;
55 let mut local_decl
= LocalDecl
::new(expr_ty
, expr_span
);
56 if mutability
== Mutability
::Not
{
57 local_decl
= local_decl
.immutable();
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.
63 if let Some(tail_info
) = this
.block_context
.currently_in_block_tail() {
64 local_decl
= local_decl
.block_tail(tail_info
);
67 ExprKind
::StaticRef { def_id, .. }
=> {
68 assert
!(!this
.hir
.tcx().is_thread_local_static(def_id
));
69 local_decl
.internal
= true;
70 local_decl
.local_info
=
71 Some(box LocalInfo
::StaticRef { def_id, is_thread_local: false }
);
73 ExprKind
::ThreadLocalRef(def_id
) => {
74 assert
!(this
.hir
.tcx().is_thread_local_static(def_id
));
75 local_decl
.internal
= true;
76 local_decl
.local_info
=
77 Some(box LocalInfo
::StaticRef { def_id, is_thread_local: true }
);
79 ExprKind
::Literal { const_id: Some(def_id), .. }
=> {
80 local_decl
.local_info
= Some(box LocalInfo
::ConstRef { def_id }
);
84 this
.local_decls
.push(local_decl
)
86 let temp_place
= Place
::from(temp
);
89 // Don't bother with StorageLive and Dead for these temporaries,
90 // they are never assigned.
91 ExprKind
::Break { .. }
| ExprKind
::Continue { .. }
| ExprKind
::Return { .. }
=> (),
92 ExprKind
::Block { body: hir::Block { expr: None, targeted_by_break: false, .. }
}
93 if expr_ty
.is_never() => {}
96 .push(block
, Statement { source_info, kind: StatementKind::StorageLive(temp) }
);
98 // In constants, `temp_lifetime` is `None` for temporaries that
99 // live for the `'static` lifetime. Thus we do not drop these
100 // temporaries and simply leak them.
101 // This is equivalent to what `let x = &foo();` does in
102 // functions. The temporary is lifted to their surrounding
103 // scope. In a function that means the temporary lives until
104 // just before the function returns. In constants that means it
105 // outlives the constant's initialization value computation.
106 // Anything outliving a constant must have the `'static`
107 // lifetime and live forever.
108 // Anything with a shorter lifetime (e.g the `&foo()` in
109 // `bar(&foo())` or anything within a block will keep the
110 // regular drops just like runtime code.
111 if let Some(temp_lifetime
) = temp_lifetime
{
112 this
.schedule_drop(expr_span
, temp_lifetime
, temp
, DropKind
::Storage
);
117 unpack
!(block
= this
.into(temp_place
, block
, expr
));
119 if let Some(temp_lifetime
) = temp_lifetime
{
120 this
.schedule_drop(expr_span
, temp_lifetime
, temp
, DropKind
::Value
);