rustc_mir_build/builder/expr/
as_temp.rs1use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_hir::HirId;
5use rustc_middle::middle::region::{Scope, ScopeData};
6use rustc_middle::mir::*;
7use rustc_middle::thir::*;
8use tracing::{debug, instrument};
9
10use crate::builder::scope::DropKind;
11use crate::builder::{BlockAnd, BlockAndExtension, Builder};
12
13impl<'a, 'tcx> Builder<'a, 'tcx> {
14 pub(crate) fn as_temp(
17 &mut self,
18 block: BasicBlock,
19 temp_lifetime: TempLifetime,
20 expr_id: ExprId,
21 mutability: Mutability,
22 ) -> BlockAnd<Local> {
23 ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr_id, mutability))
27 }
28
29 #[instrument(skip(self), level = "debug")]
30 fn as_temp_inner(
31 &mut self,
32 mut block: BasicBlock,
33 temp_lifetime: TempLifetime,
34 expr_id: ExprId,
35 mutability: Mutability,
36 ) -> BlockAnd<Local> {
37 let this = self;
38
39 let expr = &this.thir[expr_id];
40 let expr_span = expr.span;
41 let source_info = this.source_info(expr_span);
42 if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
43 return this.in_scope((region_scope, source_info), lint_level, |this| {
44 this.as_temp(block, temp_lifetime, value, mutability)
45 });
46 }
47
48 let expr_ty = expr.ty;
49 let deduplicate_temps = this.fixed_temps_scope.is_some()
50 && this.fixed_temps_scope == temp_lifetime.temp_lifetime;
51 let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) {
52 *temp_index
53 } else {
54 let mut local_decl = LocalDecl::new(expr_ty, expr_span);
55 if mutability.is_not() {
56 local_decl = local_decl.immutable();
57 }
58
59 debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
60 let local_info = match expr.kind {
61 ExprKind::StaticRef { def_id, .. } => {
62 assert!(!this.tcx.is_thread_local_static(def_id));
63 LocalInfo::StaticRef { def_id, is_thread_local: false }
64 }
65 ExprKind::ThreadLocalRef(def_id) => {
66 assert!(this.tcx.is_thread_local_static(def_id));
67 LocalInfo::StaticRef { def_id, is_thread_local: true }
68 }
69 ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => {
70 LocalInfo::ConstRef { def_id }
71 }
72 _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => {
75 LocalInfo::BlockTailTemp(tail_info)
76 }
77
78 _ if let Some(Scope { data: ScopeData::IfThenRescope, local_id }) =
79 temp_lifetime.temp_lifetime =>
80 {
81 LocalInfo::IfThenRescopeTemp {
82 if_then: HirId { owner: this.hir_id.owner, local_id },
83 }
84 }
85
86 _ => LocalInfo::Boring,
87 };
88 **local_decl.local_info.as_mut().unwrap_crate_local() = local_info;
89 this.local_decls.push(local_decl)
90 };
91 debug!(?temp);
92 if deduplicate_temps {
93 this.fixed_temps.insert(expr_id, temp);
94 }
95 let temp_place = Place::from(temp);
96
97 match expr.kind {
98 ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
101 ExprKind::Block { block }
102 if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block]
103 && expr_ty.is_never() => {}
104 _ => {
105 this.cfg
106 .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
107
108 if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
122 this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
123 }
124 }
125 }
126
127 block = this.expr_into_dest(temp_place, block, expr_id).into_block();
128
129 if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
130 this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
131 }
132
133 if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible {
134 this.schedule_backwards_incompatible_drop(expr_span, backwards_incompatible, temp);
135 }
136
137 block.and(temp)
138 }
139}