]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::build; |
6a06907d | 2 | use crate::build::expr::as_place::PlaceBuilder; |
dc9dc135 | 3 | use crate::build::scope::DropKind; |
6a06907d | 4 | use crate::thir::{build_thir, Arena, BindingMode, Expr, LintLevel, Pat, PatKind}; |
74b04a01 | 5 | use rustc_attr::{self as attr, UnwindAttr}; |
ba9703b0 | 6 | use rustc_errors::ErrorReported; |
dfeec247 | 7 | use rustc_hir as hir; |
f9f354fc | 8 | use rustc_hir::def_id::{DefId, LocalDefId}; |
3dfed10e | 9 | use rustc_hir::lang_items::LangItem; |
dfeec247 XL |
10 | use rustc_hir::{GeneratorKind, HirIdMap, Node}; |
11 | use rustc_index::vec::{Idx, IndexVec}; | |
6a06907d | 12 | use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; |
fc512014 | 13 | use rustc_middle::hir::place::PlaceBase as HirPlaceBase; |
ba9703b0 XL |
14 | use rustc_middle::middle::region; |
15 | use rustc_middle::mir::*; | |
16 | use rustc_middle::ty::subst::Subst; | |
6a06907d XL |
17 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; |
18 | use rustc_span::symbol::{kw, sym}; | |
dfeec247 XL |
19 | use rustc_span::Span; |
20 | use rustc_target::spec::abi::Abi; | |
83c7162d | 21 | use rustc_target::spec::PanicStrategy; |
3157f602 | 22 | |
0bf4aa26 XL |
23 | use super::lints; |
24 | ||
3dfed10e XL |
25 | crate fn mir_built<'tcx>( |
26 | tcx: TyCtxt<'tcx>, | |
27 | def: ty::WithOptConstParam<LocalDefId>, | |
fc512014 | 28 | ) -> &'tcx rustc_data_structures::steal::Steal<Body<'tcx>> { |
3dfed10e XL |
29 | if let Some(def) = def.try_upgrade(tcx) { |
30 | return tcx.mir_built(def); | |
31 | } | |
32 | ||
29967ef6 XL |
33 | let mut body = mir_build(tcx, def); |
34 | if def.const_param_did.is_some() { | |
35 | assert!(matches!(body.source.instance, ty::InstanceDef::Item(_))); | |
36 | body.source = MirSource::from_instance(ty::InstanceDef::Item(def.to_global())); | |
37 | } | |
38 | ||
39 | tcx.alloc_steal_mir(body) | |
dfeec247 XL |
40 | } |
41 | ||
9fa01778 | 42 | /// Construct the MIR for a given `DefId`. |
3dfed10e XL |
43 | fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> { |
44 | let id = tcx.hir().local_def_id_to_hir_id(def.did); | |
6a06907d XL |
45 | let body_owner_kind = tcx.hir().body_owner_kind(id); |
46 | let typeck_results = tcx.typeck_opt_const_arg(def); | |
3157f602 | 47 | |
7cac9316 | 48 | // Figure out what primary body this item has. |
3dfed10e | 49 | let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { |
dfeec247 | 50 | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => { |
3dfed10e | 51 | (*body_id, decl.output.span(), None) |
0bf4aa26 | 52 | } |
dfeec247 XL |
53 | Node::Item(hir::Item { |
54 | kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id), | |
3dfed10e | 55 | span, |
dfeec247 XL |
56 | .. |
57 | }) | |
58 | | Node::ImplItem(hir::ImplItem { | |
ba9703b0 | 59 | kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, body_id), |
3dfed10e | 60 | span, |
dfeec247 XL |
61 | .. |
62 | }) | |
63 | | Node::TraitItem(hir::TraitItem { | |
ba9703b0 | 64 | kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)), |
3dfed10e | 65 | span, |
dfeec247 | 66 | .. |
3dfed10e XL |
67 | }) => { |
68 | // Use the `Span` of the `Item/ImplItem/TraitItem` as the body span, | |
69 | // since the def span of a function does not include the body | |
70 | (*body_id, decl.output.span(), Some(*span)) | |
71 | } | |
ba9703b0 XL |
72 | Node::Item(hir::Item { |
73 | kind: hir::ItemKind::Static(ty, _, body_id) | hir::ItemKind::Const(ty, body_id), | |
74 | .. | |
75 | }) | |
e74abb32 | 76 | | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. }) |
dfeec247 XL |
77 | | Node::TraitItem(hir::TraitItem { |
78 | kind: hir::TraitItemKind::Const(ty, Some(body_id)), | |
79 | .. | |
3dfed10e | 80 | }) => (*body_id, ty.span, None), |
fc512014 XL |
81 | Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { |
82 | (*body, tcx.hir().span(*hir_id), None) | |
83 | } | |
0bf4aa26 | 84 | |
3dfed10e | 85 | _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), |
7cac9316 XL |
86 | }; |
87 | ||
3dfed10e XL |
88 | // If we don't have a specialized span for the body, just use the |
89 | // normal def span. | |
90 | let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id)); | |
6a06907d | 91 | let arena = Arena::default(); |
3dfed10e | 92 | |
041b39d2 | 93 | tcx.infer_ctxt().enter(|infcx| { |
6a06907d XL |
94 | let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors { |
95 | build::construct_error(&infcx, def, id, body_id, body_owner_kind) | |
96 | } else if body_owner_kind.is_fn_or_closure() { | |
7cac9316 XL |
97 | // fetch the fully liberated fn signature (that is, all bound |
98 | // types/lifetimes replaced) | |
6a06907d | 99 | let fn_sig = typeck_results.liberated_fn_sigs()[id]; |
416331ca | 100 | let fn_def_id = tcx.hir().local_def_id(id); |
7cac9316 | 101 | |
74b04a01 XL |
102 | let safety = match fn_sig.unsafety { |
103 | hir::Unsafety::Normal => Safety::Safe, | |
104 | hir::Unsafety::Unsafe => Safety::FnUnsafe, | |
105 | }; | |
106 | ||
107 | let body = tcx.hir().body(body_id); | |
6a06907d | 108 | let thir = build_thir(tcx, def, &arena, &body.value); |
0731742a | 109 | let ty = tcx.type_of(fn_def_id); |
7cac9316 | 110 | let mut abi = fn_sig.abi; |
1b1a35ee | 111 | let implicit_argument = match ty.kind() { |
b7449926 | 112 | ty::Closure(..) => { |
ea8adc8c XL |
113 | // HACK(eddyb) Avoid having RustCall on closures, |
114 | // as it adds unnecessary (and wrong) auto-tupling. | |
115 | abi = Abi::Rust; | |
74b04a01 | 116 | vec![ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None)] |
ea8adc8c | 117 | } |
b7449926 | 118 | ty::Generator(..) => { |
3dfed10e | 119 | let gen_ty = tcx.typeck_body(body_id).node_type(id); |
ea8adc8c | 120 | |
74b04a01 XL |
121 | // The resume argument may be missing, in that case we need to provide it here. |
122 | // It will always be `()` in this case. | |
123 | if body.params.is_empty() { | |
124 | vec![ | |
125 | ArgInfo(gen_ty, None, None, None), | |
126 | ArgInfo(tcx.mk_unit(), None, None, None), | |
127 | ] | |
128 | } else { | |
129 | vec![ArgInfo(gen_ty, None, None, None)] | |
130 | } | |
131 | } | |
132 | _ => vec![], | |
7cac9316 XL |
133 | }; |
134 | ||
dfeec247 XL |
135 | let explicit_arguments = body.params.iter().enumerate().map(|(index, arg)| { |
136 | let owner_id = tcx.hir().body_owner(body_id); | |
137 | let opt_ty_info; | |
138 | let self_arg; | |
139 | if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) { | |
140 | opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span); | |
141 | self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() { | |
142 | match fn_decl.implicit_self { | |
143 | hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm), | |
144 | hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut), | |
145 | hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef), | |
146 | hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef), | |
147 | _ => None, | |
94b46f34 | 148 | } |
dfeec247 XL |
149 | } else { |
150 | None | |
151 | }; | |
152 | } else { | |
153 | opt_ty_info = None; | |
154 | self_arg = None; | |
155 | } | |
dc9dc135 | 156 | |
dfeec247 XL |
157 | // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` |
158 | // (as it's created inside the body itself, not passed in from outside). | |
159 | let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() { | |
3dfed10e | 160 | let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(arg.span)); |
dfeec247 | 161 | |
ba9703b0 | 162 | tcx.type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()]) |
dfeec247 XL |
163 | } else { |
164 | fn_sig.inputs()[index] | |
165 | }; | |
e74abb32 | 166 | |
dfeec247 XL |
167 | ArgInfo(ty, opt_ty_info, Some(&arg), self_arg) |
168 | }); | |
7cac9316 XL |
169 | |
170 | let arguments = implicit_argument.into_iter().chain(explicit_arguments); | |
ea8adc8c | 171 | |
dc9dc135 | 172 | let (yield_ty, return_ty) = if body.generator_kind.is_some() { |
3dfed10e | 173 | let gen_ty = tcx.typeck_body(body_id).node_type(id); |
1b1a35ee | 174 | let gen_sig = match gen_ty.kind() { |
ba9703b0 | 175 | ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(), |
dfeec247 | 176 | _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty), |
ff7c6d11 | 177 | }; |
ea8adc8c XL |
178 | (Some(gen_sig.yield_ty), gen_sig.return_ty) |
179 | } else { | |
180 | (None, fn_sig.output()) | |
181 | }; | |
182 | ||
60c5eb7d | 183 | let mut mir = build::construct_fn( |
6a06907d XL |
184 | &infcx, |
185 | def, | |
60c5eb7d XL |
186 | id, |
187 | arguments, | |
188 | safety, | |
189 | abi, | |
190 | return_ty, | |
191 | return_ty_span, | |
192 | body, | |
6a06907d | 193 | thir, |
fc512014 | 194 | span_with_body, |
60c5eb7d | 195 | ); |
6a06907d XL |
196 | if yield_ty.is_some() { |
197 | mir.generator.as_mut().unwrap().yield_ty = yield_ty; | |
198 | } | |
60c5eb7d | 199 | mir |
7cac9316 | 200 | } else { |
48663c56 XL |
201 | // Get the revealed type of this const. This is *not* the adjusted |
202 | // type of its body, which may be a subtype of this type. For | |
203 | // example: | |
204 | // | |
205 | // fn foo(_: &()) {} | |
206 | // static X: fn(&'static ()) = foo; | |
207 | // | |
208 | // The adjusted type of the body of X is `for<'a> fn(&'a ())` which | |
209 | // is not the same as the type of X. We need the type of the return | |
210 | // place to be the type of the constant because NLL typeck will | |
211 | // equate them. | |
212 | ||
6a06907d XL |
213 | let return_ty = typeck_results.node_type(id); |
214 | ||
215 | let ast_expr = &tcx.hir().body(body_id).value; | |
216 | let thir = build_thir(tcx, def, &arena, ast_expr); | |
48663c56 | 217 | |
6a06907d | 218 | build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span) |
7cac9316 XL |
219 | }; |
220 | ||
29967ef6 | 221 | lints::check(tcx, &body); |
0bf4aa26 | 222 | |
ba9703b0 XL |
223 | // The borrow checker will replace all the regions here with its own |
224 | // inference variables. There's no point having non-erased regions here. | |
225 | // The exception is `body.user_type_annotations`, which is used unmodified | |
226 | // by borrow checking. | |
227 | debug_assert!( | |
228 | !(body.local_decls.has_free_regions() | |
229 | || body.basic_blocks().has_free_regions() | |
230 | || body.var_debug_info.has_free_regions() | |
6a06907d | 231 | || body.yield_ty().has_free_regions()), |
ba9703b0 XL |
232 | "Unexpected free regions in MIR: {:?}", |
233 | body, | |
234 | ); | |
235 | ||
dc9dc135 | 236 | body |
7cac9316 XL |
237 | }) |
238 | } | |
239 | ||
7cac9316 XL |
240 | /////////////////////////////////////////////////////////////////////////// |
241 | // BuildMir -- walks a crate, looking for fn items and methods to build MIR from | |
242 | ||
416331ca XL |
243 | fn liberated_closure_env_ty( |
244 | tcx: TyCtxt<'_>, | |
dc9dc135 XL |
245 | closure_expr_id: hir::HirId, |
246 | body_id: hir::BodyId, | |
416331ca | 247 | ) -> Ty<'_> { |
3dfed10e | 248 | let closure_ty = tcx.typeck_body(body_id).node_type(closure_expr_id); |
7cac9316 | 249 | |
1b1a35ee | 250 | let (closure_def_id, closure_substs) = match *closure_ty.kind() { |
b7449926 | 251 | ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs), |
dfeec247 | 252 | _ => bug!("closure expr does not have closure type: {:?}", closure_ty), |
ff7c6d11 XL |
253 | }; |
254 | ||
255 | let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap(); | |
fc512014 | 256 | tcx.erase_late_bound_regions(closure_env_ty) |
7cac9316 | 257 | } |
b039eaaf | 258 | |
0bf4aa26 | 259 | #[derive(Debug, PartialEq, Eq)] |
dfeec247 | 260 | enum BlockFrame { |
0bf4aa26 XL |
261 | /// Evaluation is currently within a statement. |
262 | /// | |
263 | /// Examples include: | |
dc9dc135 XL |
264 | /// 1. `EXPR;` |
265 | /// 2. `let _ = EXPR;` | |
266 | /// 3. `let x = EXPR;` | |
0bf4aa26 XL |
267 | Statement { |
268 | /// If true, then statement discards result from evaluating | |
269 | /// the expression (such as examples 1 and 2 above). | |
dfeec247 | 270 | ignores_expr_result: bool, |
0bf4aa26 XL |
271 | }, |
272 | ||
273 | /// Evaluation is currently within the tail expression of a block. | |
274 | /// | |
275 | /// Example: `{ STMT_1; STMT_2; EXPR }` | |
276 | TailExpr { | |
277 | /// If true, then the surrounding context of the block ignores | |
278 | /// the result of evaluating the block's tail expression. | |
279 | /// | |
280 | /// Example: `let _ = { STMT_1; EXPR };` | |
dfeec247 | 281 | tail_result_is_ignored: bool, |
f9f354fc XL |
282 | |
283 | /// `Span` of the tail expression. | |
284 | span: Span, | |
0bf4aa26 XL |
285 | }, |
286 | ||
287 | /// Generic mark meaning that the block occurred as a subexpression | |
288 | /// where the result might be used. | |
289 | /// | |
290 | /// Examples: `foo(EXPR)`, `match EXPR { ... }` | |
291 | SubExpr, | |
292 | } | |
293 | ||
294 | impl BlockFrame { | |
295 | fn is_tail_expr(&self) -> bool { | |
296 | match *self { | |
297 | BlockFrame::TailExpr { .. } => true, | |
298 | ||
dfeec247 | 299 | BlockFrame::Statement { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
300 | } |
301 | } | |
302 | fn is_statement(&self) -> bool { | |
303 | match *self { | |
304 | BlockFrame::Statement { .. } => true, | |
305 | ||
dfeec247 | 306 | BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
307 | } |
308 | } | |
dfeec247 | 309 | } |
0bf4aa26 | 310 | |
a1dfa0c6 XL |
311 | #[derive(Debug)] |
312 | struct BlockContext(Vec<BlockFrame>); | |
313 | ||
dc9dc135 | 314 | struct Builder<'a, 'tcx> { |
6a06907d XL |
315 | tcx: TyCtxt<'tcx>, |
316 | infcx: &'a InferCtxt<'a, 'tcx>, | |
317 | typeck_results: &'tcx TypeckResults<'tcx>, | |
318 | region_scope_tree: &'tcx region::ScopeTree, | |
319 | param_env: ty::ParamEnv<'tcx>, | |
320 | ||
b039eaaf | 321 | cfg: CFG<'tcx>, |
54a0048b | 322 | |
29967ef6 | 323 | def_id: DefId, |
6a06907d XL |
324 | hir_id: hir::HirId, |
325 | check_overflow: bool, | |
54a0048b | 326 | fn_span: Span, |
c30ab7b3 | 327 | arg_count: usize, |
60c5eb7d | 328 | generator_kind: Option<GeneratorKind>, |
54a0048b | 329 | |
9fa01778 XL |
330 | /// The current set of scopes, updated as we traverse; |
331 | /// see the `scope` module for more details. | |
dc9dc135 | 332 | scopes: scope::Scopes<'tcx>, |
54a0048b | 333 | |
3dfed10e | 334 | /// The block-context: each time we build the code within an thir::Block, |
0bf4aa26 XL |
335 | /// we push a frame here tracking whether we are building a statement or |
336 | /// if we are pushing the tail expression of the block. This is used to | |
337 | /// embed information in generated temps about whether they were created | |
338 | /// for a block tail expression or not. | |
339 | /// | |
340 | /// It would be great if we could fold this into `self.scopes` | |
9fa01778 | 341 | /// somehow, but right now I think that is very tightly tied to |
0bf4aa26 XL |
342 | /// the code generation in ways that we cannot (or should not) |
343 | /// start just throwing new entries onto that vector in order to | |
344 | /// distinguish the context of EXPR1 from the context of EXPR2 in | |
9fa01778 | 345 | /// `{ STMTS; EXPR1 } + EXPR2`. |
a1dfa0c6 | 346 | block_context: BlockContext, |
0bf4aa26 | 347 | |
ea8adc8c | 348 | /// The current unsafe block in scope, even if it is hidden by |
9fa01778 | 349 | /// a `PushUnsafeBlock`. |
ea8adc8c XL |
350 | unpushed_unsafe: Safety, |
351 | ||
9fa01778 | 352 | /// The number of `push_unsafe_block` levels in scope. |
ea8adc8c XL |
353 | push_unsafe_count: usize, |
354 | ||
9fa01778 XL |
355 | /// The vector of all scopes that we have created thus far; |
356 | /// we track this for debuginfo later. | |
29967ef6 | 357 | source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, |
94b46f34 | 358 | source_scope: SourceScope, |
54a0048b | 359 | |
9fa01778 | 360 | /// The guard-context: each time we build the guard expression for |
83c7162d XL |
361 | /// a match arm, we push onto this stack, and then pop when we |
362 | /// finish building it. | |
363 | guard_context: Vec<GuardFrame>, | |
364 | ||
532ac7d7 | 365 | /// Maps `HirId`s of variable bindings to the `Local`s created for them. |
83c7162d | 366 | /// (A match binding can have two locals; the 2nd is for the arm's guard.) |
532ac7d7 | 367 | var_indices: HirIdMap<LocalsForNode>, |
c30ab7b3 | 368 | local_decls: IndexVec<Local, LocalDecl<'tcx>>, |
0731742a | 369 | canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, |
48663c56 | 370 | upvar_mutbls: Vec<Mutability>, |
ff7c6d11 | 371 | unit_temp: Option<Place<'tcx>>, |
54a0048b | 372 | |
60c5eb7d | 373 | var_debug_info: Vec<VarDebugInfo<'tcx>>, |
e9174d1e SL |
374 | } |
375 | ||
dc9dc135 | 376 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
532ac7d7 | 377 | fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool { |
83c7162d XL |
378 | self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) |
379 | } | |
380 | ||
532ac7d7 | 381 | fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local { |
83c7162d XL |
382 | self.var_indices[&id].local_id(for_guard) |
383 | } | |
384 | } | |
385 | ||
a1dfa0c6 | 386 | impl BlockContext { |
dfeec247 XL |
387 | fn new() -> Self { |
388 | BlockContext(vec![]) | |
389 | } | |
390 | fn push(&mut self, bf: BlockFrame) { | |
391 | self.0.push(bf); | |
392 | } | |
393 | fn pop(&mut self) -> Option<BlockFrame> { | |
394 | self.0.pop() | |
395 | } | |
a1dfa0c6 | 396 | |
9fa01778 | 397 | /// Traverses the frames on the `BlockContext`, searching for either |
a1dfa0c6 XL |
398 | /// the first block-tail expression frame with no intervening |
399 | /// statement frame. | |
400 | /// | |
401 | /// Notably, this skips over `SubExpr` frames; this method is | |
402 | /// meant to be used in the context of understanding the | |
403 | /// relationship of a temp (created within some complicated | |
404 | /// expression) with its containing expression, and whether the | |
405 | /// value of that *containing expression* (not the temp!) is | |
406 | /// ignored. | |
407 | fn currently_in_block_tail(&self) -> Option<BlockTailInfo> { | |
408 | for bf in self.0.iter().rev() { | |
409 | match bf { | |
410 | BlockFrame::SubExpr => continue, | |
411 | BlockFrame::Statement { .. } => break, | |
f9f354fc XL |
412 | &BlockFrame::TailExpr { tail_result_is_ignored, span } => { |
413 | return Some(BlockTailInfo { tail_result_is_ignored, span }); | |
dfeec247 | 414 | } |
a1dfa0c6 XL |
415 | } |
416 | } | |
417 | ||
ba9703b0 | 418 | None |
a1dfa0c6 XL |
419 | } |
420 | ||
421 | /// Looks at the topmost frame on the BlockContext and reports | |
422 | /// whether its one that would discard a block tail result. | |
423 | /// | |
424 | /// Unlike `currently_within_ignored_tail_expression`, this does | |
425 | /// *not* skip over `SubExpr` frames: here, we want to know | |
426 | /// whether the block result itself is discarded. | |
427 | fn currently_ignores_tail_results(&self) -> bool { | |
428 | match self.0.last() { | |
429 | // no context: conservatively assume result is read | |
430 | None => false, | |
431 | ||
432 | // sub-expression: block result feeds into some computation | |
433 | Some(BlockFrame::SubExpr) => false, | |
434 | ||
435 | // otherwise: use accumulated is_ignored state. | |
ba9703b0 | 436 | Some( |
f9f354fc | 437 | BlockFrame::TailExpr { tail_result_is_ignored: ignored, .. } |
ba9703b0 XL |
438 | | BlockFrame::Statement { ignores_expr_result: ignored }, |
439 | ) => *ignored, | |
a1dfa0c6 XL |
440 | } |
441 | } | |
442 | } | |
443 | ||
83c7162d XL |
444 | #[derive(Debug)] |
445 | enum LocalsForNode { | |
532ac7d7 | 446 | /// In the usual case, a `HirId` for an identifier maps to at most |
9fa01778 | 447 | /// one `Local` declaration. |
83c7162d | 448 | One(Local), |
8faf50e0 XL |
449 | |
450 | /// The exceptional case is identifiers in a match arm's pattern | |
451 | /// that are referenced in a guard of that match arm. For these, | |
9fa01778 | 452 | /// we have `2` Locals. |
8faf50e0 XL |
453 | /// |
454 | /// * `for_arm_body` is the Local used in the arm body (which is | |
455 | /// just like the `One` case above), | |
456 | /// | |
457 | /// * `ref_for_guard` is the Local used in the arm's guard (which | |
458 | /// is a reference to a temp that is an alias of | |
459 | /// `for_arm_body`). | |
9fa01778 | 460 | ForGuard { ref_for_guard: Local, for_arm_body: Local }, |
83c7162d XL |
461 | } |
462 | ||
463 | #[derive(Debug)] | |
464 | struct GuardFrameLocal { | |
532ac7d7 | 465 | id: hir::HirId, |
83c7162d XL |
466 | } |
467 | ||
468 | impl GuardFrameLocal { | |
532ac7d7 | 469 | fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self { |
74b04a01 | 470 | GuardFrameLocal { id } |
83c7162d XL |
471 | } |
472 | } | |
473 | ||
474 | #[derive(Debug)] | |
475 | struct GuardFrame { | |
476 | /// These are the id's of names that are bound by patterns of the | |
477 | /// arm of *this* guard. | |
478 | /// | |
479 | /// (Frames higher up the stack will have the id's bound in arms | |
480 | /// further out, such as in a case like: | |
481 | /// | |
482 | /// match E1 { | |
483 | /// P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1, | |
484 | /// } | |
485 | /// | |
9fa01778 | 486 | /// here, when building for FIXME. |
83c7162d XL |
487 | locals: Vec<GuardFrameLocal>, |
488 | } | |
489 | ||
9fa01778 XL |
490 | /// `ForGuard` indicates whether we are talking about: |
491 | /// 1. The variable for use outside of guard expressions, or | |
492 | /// 2. The temp that holds reference to (1.), which is actually what the | |
493 | /// guard expressions see. | |
83c7162d XL |
494 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
495 | enum ForGuard { | |
94b46f34 | 496 | RefWithinGuard, |
83c7162d XL |
497 | OutsideGuard, |
498 | } | |
499 | ||
500 | impl LocalsForNode { | |
501 | fn local_id(&self, for_guard: ForGuard) -> Local { | |
502 | match (self, for_guard) { | |
dfeec247 XL |
503 | (&LocalsForNode::One(local_id), ForGuard::OutsideGuard) |
504 | | ( | |
505 | &LocalsForNode::ForGuard { ref_for_guard: local_id, .. }, | |
506 | ForGuard::RefWithinGuard, | |
507 | ) | |
508 | | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => { | |
509 | local_id | |
510 | } | |
83c7162d | 511 | |
dfeec247 XL |
512 | (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => { |
513 | bug!("anything with one local should never be within a guard.") | |
514 | } | |
83c7162d XL |
515 | } |
516 | } | |
517 | } | |
518 | ||
b039eaaf | 519 | struct CFG<'tcx> { |
3157f602 XL |
520 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
521 | } | |
522 | ||
e74abb32 | 523 | rustc_index::newtype_index! { |
dfeec247 | 524 | struct ScopeId { .. } |
b7449926 | 525 | } |
e9174d1e SL |
526 | |
527 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
528 | /// The `BlockAnd` "monad" packages up the new basic block along with a |
529 | /// produced value (sometimes just unit, of course). The `unpack!` | |
530 | /// macro (and methods below) makes working with `BlockAnd` much more | |
531 | /// convenient. | |
e9174d1e | 532 | |
83c7162d | 533 | #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] |
7cac9316 | 534 | struct BlockAnd<T>(BasicBlock, T); |
e9174d1e | 535 | |
92a42be0 SL |
536 | trait BlockAndExtension { |
537 | fn and<T>(self, v: T) -> BlockAnd<T>; | |
538 | fn unit(self) -> BlockAnd<()>; | |
539 | } | |
540 | ||
541 | impl BlockAndExtension for BasicBlock { | |
e9174d1e SL |
542 | fn and<T>(self, v: T) -> BlockAnd<T> { |
543 | BlockAnd(self, v) | |
544 | } | |
545 | ||
546 | fn unit(self) -> BlockAnd<()> { | |
547 | BlockAnd(self, ()) | |
548 | } | |
549 | } | |
550 | ||
551 | /// Update a block pointer and return the value. | |
552 | /// Use it like `let x = unpack!(block = self.foo(block, foo))`. | |
553 | macro_rules! unpack { | |
dfeec247 XL |
554 | ($x:ident = $c:expr) => {{ |
555 | let BlockAnd(b, v) = $c; | |
556 | $x = b; | |
557 | v | |
558 | }}; | |
559 | ||
560 | ($c:expr) => {{ | |
561 | let BlockAnd(b, ()) = $c; | |
562 | b | |
563 | }}; | |
e9174d1e SL |
564 | } |
565 | ||
6a06907d | 566 | fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool { |
e74abb32 | 567 | // Validate `#[unwind]` syntax regardless of platform-specific panic strategy. |
f9f354fc | 568 | let attrs = &tcx.get_attrs(fn_def_id.to_def_id()); |
3dfed10e | 569 | let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs); |
532ac7d7 | 570 | |
e74abb32 | 571 | // We never unwind, so it's not relevant to stop an unwind. |
dfeec247 XL |
572 | if tcx.sess.panic_strategy() != PanicStrategy::Unwind { |
573 | return false; | |
574 | } | |
ff7c6d11 | 575 | |
532ac7d7 | 576 | match unwind_attr { |
6a06907d | 577 | // If an `#[unwind]` attribute was found, we should adhere to it. |
0531ce1d XL |
578 | Some(UnwindAttr::Allowed) => false, |
579 | Some(UnwindAttr::Aborts) => true, | |
6a06907d XL |
580 | // If no attribute was found and the panic strategy is `unwind`, then we should examine |
581 | // the function's ABI string to determine whether it should abort upon panic. | |
36d6ef2b | 582 | None if tcx.features().c_unwind => { |
6a06907d XL |
583 | use Abi::*; |
584 | match abi { | |
585 | // In the case of ABI's that have an `-unwind` equivalent, check whether the ABI | |
586 | // permits unwinding. If so, we should not abort. Otherwise, we should. | |
587 | C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { | |
588 | !unwind | |
589 | } | |
590 | // Rust and `rust-call` functions are allowed to unwind, and should not abort. | |
591 | Rust | RustCall => false, | |
592 | // Other ABI's should abort. | |
593 | Cdecl | |
594 | | Fastcall | |
595 | | Vectorcall | |
596 | | Aapcs | |
597 | | Win64 | |
598 | | SysV64 | |
599 | | PtxKernel | |
600 | | Msp430Interrupt | |
601 | | X86Interrupt | |
602 | | AmdGpuKernel | |
603 | | EfiApi | |
604 | | AvrInterrupt | |
605 | | AvrNonBlockingInterrupt | |
606 | | CCmseNonSecureCall | |
607 | | RustIntrinsic | |
608 | | PlatformIntrinsic | |
609 | | Unadjusted => true, | |
610 | } | |
611 | } | |
36d6ef2b XL |
612 | // If the `c_unwind` feature gate is not active, follow the behavior that was in place |
613 | // prior to #76570. This is a special case: some functions have a C ABI but are meant to | |
614 | // unwind anyway. Don't stop them. | |
615 | None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)` | |
0531ce1d | 616 | } |
ff7c6d11 XL |
617 | } |
618 | ||
e9174d1e | 619 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 620 | /// the main entry point for building MIR for a function |
e9174d1e | 621 | |
dfeec247 XL |
622 | struct ArgInfo<'tcx>( |
623 | Ty<'tcx>, | |
624 | Option<Span>, | |
625 | Option<&'tcx hir::Param<'tcx>>, | |
626 | Option<ImplicitSelfKind>, | |
627 | ); | |
dc9dc135 | 628 | |
6a06907d XL |
629 | fn construct_fn<'tcx, A>( |
630 | infcx: &InferCtxt<'_, 'tcx>, | |
631 | fn_def: ty::WithOptConstParam<LocalDefId>, | |
dc9dc135 XL |
632 | fn_id: hir::HirId, |
633 | arguments: A, | |
634 | safety: Safety, | |
635 | abi: Abi, | |
636 | return_ty: Ty<'tcx>, | |
dc9dc135 | 637 | return_ty_span: Span, |
dfeec247 | 638 | body: &'tcx hir::Body<'tcx>, |
6a06907d | 639 | expr: &Expr<'_, 'tcx>, |
fc512014 | 640 | span_with_body: Span, |
dc9dc135 XL |
641 | ) -> Body<'tcx> |
642 | where | |
dfeec247 | 643 | A: Iterator<Item = ArgInfo<'tcx>>, |
a7813a04 | 644 | { |
c30ab7b3 SL |
645 | let arguments: Vec<_> = arguments.collect(); |
646 | ||
6a06907d XL |
647 | let tcx = infcx.tcx; |
648 | let span = tcx.hir().span(fn_id); | |
8faf50e0 | 649 | |
dfeec247 | 650 | let mut builder = Builder::new( |
6a06907d XL |
651 | infcx, |
652 | fn_def, | |
653 | fn_id, | |
3dfed10e | 654 | span_with_body, |
ea8adc8c XL |
655 | arguments.len(), |
656 | safety, | |
8faf50e0 | 657 | return_ty, |
0bf4aa26 | 658 | return_ty_span, |
dfeec247 XL |
659 | body.generator_kind, |
660 | ); | |
ea8adc8c | 661 | |
dfeec247 XL |
662 | let call_site_scope = |
663 | region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite }; | |
664 | let arg_scope = | |
665 | region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments }; | |
041b39d2 | 666 | let source_info = builder.source_info(span); |
ea8adc8c | 667 | let call_site_s = (call_site_scope, source_info); |
29967ef6 XL |
668 | unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { |
669 | let arg_scope_s = (arg_scope, source_info); | |
670 | // Attribute epilogue to function's closing brace | |
671 | let fn_end = span_with_body.shrink_to_hi(); | |
672 | let return_block = | |
673 | unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { | |
674 | Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { | |
675 | builder.args_and_body( | |
676 | START_BLOCK, | |
6a06907d | 677 | fn_def.did.to_def_id(), |
29967ef6 XL |
678 | &arguments, |
679 | arg_scope, | |
6a06907d | 680 | expr, |
29967ef6 XL |
681 | ) |
682 | })) | |
683 | })); | |
684 | let source_info = builder.source_info(fn_end); | |
685 | builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); | |
6a06907d | 686 | let should_abort = should_abort_on_panic(tcx, fn_def.did, abi); |
29967ef6 XL |
687 | builder.build_drop_trees(should_abort); |
688 | return_block.unit() | |
689 | })); | |
a7813a04 | 690 | |
ba9703b0 | 691 | let spread_arg = if abi == Abi::RustCall { |
476ff2be | 692 | // RustCall pseudo-ABI untuples the last argument. |
ba9703b0 XL |
693 | Some(Local::new(arguments.len())) |
694 | } else { | |
695 | None | |
696 | }; | |
6a06907d | 697 | debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id())); |
54a0048b | 698 | |
60c5eb7d | 699 | let mut body = builder.finish(); |
dc9dc135 XL |
700 | body.spread_arg = spread_arg; |
701 | body | |
a7813a04 XL |
702 | } |
703 | ||
dc9dc135 | 704 | fn construct_const<'a, 'tcx>( |
6a06907d XL |
705 | infcx: &'a InferCtxt<'a, 'tcx>, |
706 | expr: &Expr<'_, 'tcx>, | |
707 | def: ty::WithOptConstParam<LocalDefId>, | |
708 | hir_id: hir::HirId, | |
48663c56 XL |
709 | const_ty: Ty<'tcx>, |
710 | const_ty_span: Span, | |
dc9dc135 | 711 | ) -> Body<'tcx> { |
6a06907d XL |
712 | let tcx = infcx.tcx; |
713 | let span = tcx.hir().span(hir_id); | |
fc512014 | 714 | let mut builder = |
6a06907d | 715 | Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None); |
a7813a04 | 716 | |
a7813a04 | 717 | let mut block = START_BLOCK; |
6a06907d | 718 | unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr)); |
a7813a04 | 719 | |
7cac9316 XL |
720 | let source_info = builder.source_info(span); |
721 | builder.cfg.terminate(block, source_info, TerminatorKind::Return); | |
a7813a04 | 722 | |
29967ef6 | 723 | builder.build_drop_trees(false); |
ff7c6d11 | 724 | |
60c5eb7d | 725 | builder.finish() |
e9174d1e SL |
726 | } |
727 | ||
74b04a01 XL |
728 | /// Construct MIR for a item that has had errors in type checking. |
729 | /// | |
730 | /// This is required because we may still want to run MIR passes on an item | |
731 | /// with type errors, but normal MIR construction can't handle that in general. | |
6a06907d XL |
732 | fn construct_error<'a, 'tcx>( |
733 | infcx: &'a InferCtxt<'a, 'tcx>, | |
734 | def: ty::WithOptConstParam<LocalDefId>, | |
735 | hir_id: hir::HirId, | |
736 | body_id: hir::BodyId, | |
737 | body_owner_kind: hir::BodyOwnerKind, | |
738 | ) -> Body<'tcx> { | |
739 | let tcx = infcx.tcx; | |
740 | let span = tcx.hir().span(hir_id); | |
f035d41b | 741 | let ty = tcx.ty_error(); |
6a06907d XL |
742 | let generator_kind = tcx.hir().body(body_id).generator_kind; |
743 | let num_params = match body_owner_kind { | |
744 | hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len(), | |
74b04a01 | 745 | hir::BodyOwnerKind::Closure => { |
6a06907d | 746 | if generator_kind.is_some() { |
74b04a01 XL |
747 | // Generators have an implicit `self` parameter *and* a possibly |
748 | // implicit resume parameter. | |
749 | 2 | |
750 | } else { | |
751 | // The implicit self parameter adds another local in MIR. | |
6a06907d | 752 | 1 + tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len() |
74b04a01 XL |
753 | } |
754 | } | |
755 | hir::BodyOwnerKind::Const => 0, | |
756 | hir::BodyOwnerKind::Static(_) => 0, | |
757 | }; | |
fc512014 | 758 | let mut builder = |
6a06907d | 759 | Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind); |
8bb4bdeb | 760 | let source_info = builder.source_info(span); |
74b04a01 XL |
761 | // Some MIR passes will expect the number of parameters to match the |
762 | // function declaration. | |
763 | for _ in 0..num_params { | |
f9f354fc | 764 | builder.local_decls.push(LocalDecl::with_source_info(ty, source_info)); |
74b04a01 | 765 | } |
8bb4bdeb | 766 | builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); |
74b04a01 | 767 | let mut body = builder.finish(); |
6a06907d | 768 | body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty)); |
74b04a01 | 769 | body |
8bb4bdeb XL |
770 | } |
771 | ||
dc9dc135 | 772 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
dfeec247 | 773 | fn new( |
6a06907d XL |
774 | infcx: &'a InferCtxt<'a, 'tcx>, |
775 | def: ty::WithOptConstParam<LocalDefId>, | |
776 | hir_id: hir::HirId, | |
dfeec247 XL |
777 | span: Span, |
778 | arg_count: usize, | |
779 | safety: Safety, | |
780 | return_ty: Ty<'tcx>, | |
781 | return_span: Span, | |
782 | generator_kind: Option<GeneratorKind>, | |
783 | ) -> Builder<'a, 'tcx> { | |
6a06907d XL |
784 | let tcx = infcx.tcx; |
785 | let attrs = tcx.hir().attrs(hir_id); | |
786 | // Some functions always have overflow checks enabled, | |
787 | // however, they may not get codegen'd, depending on | |
788 | // the settings for the crate they are codegened in. | |
789 | let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); | |
790 | // Respect -C overflow-checks. | |
791 | check_overflow |= tcx.sess.overflow_checks(); | |
792 | // Constants always need overflow checks. | |
793 | check_overflow |= matches!( | |
794 | tcx.hir().body_owner_kind(hir_id), | |
795 | hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) | |
796 | ); | |
797 | ||
798 | let lint_level = LintLevel::Explicit(hir_id); | |
a7813a04 | 799 | let mut builder = Builder { |
6a06907d XL |
800 | tcx, |
801 | infcx, | |
802 | typeck_results: tcx.typeck_opt_const_arg(def), | |
803 | region_scope_tree: tcx.region_scope_tree(def.did), | |
804 | param_env: tcx.param_env(def.did), | |
805 | def_id: def.did.to_def_id(), | |
806 | hir_id, | |
807 | check_overflow, | |
3157f602 | 808 | cfg: CFG { basic_blocks: IndexVec::new() }, |
a7813a04 | 809 | fn_span: span, |
3b2f2976 | 810 | arg_count, |
60c5eb7d | 811 | generator_kind, |
29967ef6 | 812 | scopes: scope::Scopes::new(), |
a1dfa0c6 | 813 | block_context: BlockContext::new(), |
94b46f34 XL |
814 | source_scopes: IndexVec::new(), |
815 | source_scope: OUTERMOST_SOURCE_SCOPE, | |
83c7162d | 816 | guard_context: vec![], |
ea8adc8c XL |
817 | push_unsafe_count: 0, |
818 | unpushed_unsafe: safety, | |
f9f354fc | 819 | local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), |
0731742a | 820 | canonical_user_type_annotations: IndexVec::new(), |
60c5eb7d | 821 | upvar_mutbls: vec![], |
a1dfa0c6 | 822 | var_indices: Default::default(), |
a7813a04 | 823 | unit_temp: None, |
60c5eb7d | 824 | var_debug_info: vec![], |
a7813a04 XL |
825 | }; |
826 | ||
827 | assert_eq!(builder.cfg.start_new_block(), START_BLOCK); | |
ea8adc8c | 828 | assert_eq!( |
94b46f34 | 829 | builder.new_source_scope(span, lint_level, Some(safety)), |
dfeec247 XL |
830 | OUTERMOST_SOURCE_SCOPE |
831 | ); | |
94b46f34 | 832 | builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None; |
a7813a04 XL |
833 | |
834 | builder | |
835 | } | |
836 | ||
60c5eb7d | 837 | fn finish(self) -> Body<'tcx> { |
a7813a04 XL |
838 | for (index, block) in self.cfg.basic_blocks.iter().enumerate() { |
839 | if block.terminator.is_none() { | |
840 | span_bug!(self.fn_span, "no terminator on block {:?}", index); | |
841 | } | |
842 | } | |
843 | ||
dc9dc135 | 844 | Body::new( |
29967ef6 | 845 | MirSource::item(self.def_id), |
0731742a XL |
846 | self.cfg.basic_blocks, |
847 | self.source_scopes, | |
0731742a XL |
848 | self.local_decls, |
849 | self.canonical_user_type_annotations, | |
850 | self.arg_count, | |
60c5eb7d | 851 | self.var_debug_info, |
0731742a | 852 | self.fn_span, |
dfeec247 | 853 | self.generator_kind, |
476ff2be | 854 | ) |
a7813a04 XL |
855 | } |
856 | ||
dfeec247 XL |
857 | fn args_and_body( |
858 | &mut self, | |
859 | mut block: BasicBlock, | |
860 | fn_def_id: DefId, | |
861 | arguments: &[ArgInfo<'tcx>], | |
862 | argument_scope: region::Scope, | |
6a06907d | 863 | expr: &Expr<'_, 'tcx>, |
dfeec247 | 864 | ) -> BlockAnd<()> { |
c30ab7b3 | 865 | // Allocate locals for the function arguments |
416331ca | 866 | for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { |
f9f354fc XL |
867 | let source_info = |
868 | SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span)); | |
869 | let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info)); | |
60c5eb7d XL |
870 | |
871 | // If this is a simple binding pattern, give debuginfo a nice name. | |
872 | if let Some(arg) = arg_opt { | |
873 | if let Some(ident) = arg.pat.simple_ident() { | |
874 | self.var_debug_info.push(VarDebugInfo { | |
875 | name: ident.name, | |
876 | source_info, | |
fc512014 | 877 | value: VarDebugInfoContents::Place(arg_local.into()), |
60c5eb7d XL |
878 | }); |
879 | } | |
880 | } | |
881 | } | |
882 | ||
6a06907d | 883 | let tcx = self.tcx; |
60c5eb7d | 884 | let tcx_hir = tcx.hir(); |
6a06907d | 885 | let hir_typeck_results = self.typeck_results; |
60c5eb7d XL |
886 | |
887 | // In analyze_closure() in upvar.rs we gathered a list of upvars used by a | |
6a06907d | 888 | // indexed closure and we stored in a map called closure_min_captures in TypeckResults |
60c5eb7d XL |
889 | // with the closure's DefId. Here, we run through that vec of UpvarIds for |
890 | // the given closure and use the necessary information to create upvar | |
891 | // debuginfo and to fill `self.upvar_mutbls`. | |
fc512014 | 892 | if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { |
60c5eb7d XL |
893 | let closure_env_arg = Local::new(1); |
894 | let mut closure_env_projs = vec![]; | |
895 | let mut closure_ty = self.local_decls[closure_env_arg].ty; | |
1b1a35ee | 896 | if let ty::Ref(_, ty, _) = closure_ty.kind() { |
60c5eb7d XL |
897 | closure_env_projs.push(ProjectionElem::Deref); |
898 | closure_ty = ty; | |
899 | } | |
1b1a35ee | 900 | let upvar_substs = match closure_ty.kind() { |
ba9703b0 XL |
901 | ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), |
902 | ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), | |
dfeec247 | 903 | _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), |
60c5eb7d | 904 | }; |
fc512014 | 905 | let capture_tys = upvar_substs.upvar_tys(); |
5869c6ff XL |
906 | let captures_with_tys = |
907 | hir_typeck_results.closure_min_captures_flattened(fn_def_id).zip(capture_tys); | |
fc512014 XL |
908 | |
909 | self.upvar_mutbls = captures_with_tys | |
dfeec247 | 910 | .enumerate() |
fc512014 XL |
911 | .map(|(i, (captured_place, ty))| { |
912 | let capture = captured_place.info.capture_kind; | |
913 | let var_id = match captured_place.place.base { | |
914 | HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, | |
5869c6ff | 915 | _ => bug!("Expected an upvar"), |
fc512014 | 916 | }; |
dfeec247 | 917 | |
5869c6ff | 918 | let mutability = captured_place.mutability; |
fc512014 XL |
919 | |
920 | // FIXME(project-rfc-2229#8): Store more precise information | |
5869c6ff | 921 | let mut name = kw::Empty; |
dfeec247 XL |
922 | if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { |
923 | if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { | |
924 | name = ident.name; | |
60c5eb7d XL |
925 | } |
926 | } | |
60c5eb7d | 927 | |
dfeec247 XL |
928 | let mut projs = closure_env_projs.clone(); |
929 | projs.push(ProjectionElem::Field(Field::new(i), ty)); | |
930 | match capture { | |
1b1a35ee | 931 | ty::UpvarCapture::ByValue(_) => {} |
dfeec247 XL |
932 | ty::UpvarCapture::ByRef(..) => { |
933 | projs.push(ProjectionElem::Deref); | |
934 | } | |
935 | }; | |
60c5eb7d | 936 | |
dfeec247 XL |
937 | self.var_debug_info.push(VarDebugInfo { |
938 | name, | |
f9f354fc | 939 | source_info: SourceInfo::outermost(tcx_hir.span(var_id)), |
fc512014 | 940 | value: VarDebugInfoContents::Place(Place { |
74b04a01 | 941 | local: closure_env_arg, |
dfeec247 | 942 | projection: tcx.intern_place_elems(&projs), |
fc512014 | 943 | }), |
dfeec247 | 944 | }); |
60c5eb7d | 945 | |
dfeec247 XL |
946 | mutability |
947 | }) | |
948 | .collect(); | |
c30ab7b3 SL |
949 | } |
950 | ||
3157f602 | 951 | let mut scope = None; |
c30ab7b3 | 952 | // Bind the argument patterns |
94b46f34 | 953 | for (index, arg_info) in arguments.iter().enumerate() { |
ff7c6d11 | 954 | // Function arguments always get the first Local indices after the return place |
abe05a73 | 955 | let local = Local::new(index + 1); |
dc9dc135 | 956 | let place = Place::from(local); |
e74abb32 | 957 | let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info; |
c30ab7b3 | 958 | |
0731742a XL |
959 | // Make sure we drop (parts of) the argument even when not matched on. |
960 | self.schedule_drop( | |
6a06907d | 961 | arg_opt.as_ref().map_or(expr.span, |arg| arg.pat.span), |
dfeec247 XL |
962 | argument_scope, |
963 | local, | |
964 | DropKind::Value, | |
0731742a XL |
965 | ); |
966 | ||
416331ca | 967 | if let Some(arg) = arg_opt { |
6a06907d XL |
968 | let pat = match tcx.hir().get(arg.pat.hir_id) { |
969 | Node::Pat(pat) | Node::Binding(pat) => pat, | |
970 | node => bug!("pattern became {:?}", node), | |
971 | }; | |
972 | let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat); | |
416331ca | 973 | let original_source_scope = self.source_scope; |
8faf50e0 | 974 | let span = pattern.span; |
416331ca | 975 | self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); |
abe05a73 XL |
976 | match *pattern.kind { |
977 | // Don't introduce extra copies for simple bindings | |
e74abb32 | 978 | PatKind::Binding { |
dc9dc135 XL |
979 | mutability, |
980 | var, | |
981 | mode: BindingMode::ByValue, | |
982 | subpattern: None, | |
983 | .. | |
984 | } => { | |
abe05a73 | 985 | self.local_decls[local].mutability = mutability; |
416331ca | 986 | self.local_decls[local].source_info.scope = self.source_scope; |
dfeec247 | 987 | self.local_decls[local].local_info = if let Some(kind) = self_binding { |
f035d41b XL |
988 | Some(box LocalInfo::User(ClearCrossCrate::Set( |
989 | BindingForm::ImplicitSelf(*kind), | |
990 | ))) | |
dfeec247 | 991 | } else { |
74b04a01 | 992 | let binding_mode = ty::BindingMode::BindByValue(mutability); |
f9f354fc | 993 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( |
dfeec247 XL |
994 | VarBindingForm { |
995 | binding_mode, | |
996 | opt_ty_info, | |
997 | opt_match_place: Some((Some(place), span)), | |
998 | pat_span: span, | |
999 | }, | |
f9f354fc | 1000 | )))) |
dfeec247 | 1001 | }; |
83c7162d | 1002 | self.var_indices.insert(var, LocalsForNode::One(local)); |
abe05a73 XL |
1003 | } |
1004 | _ => { | |
dc9dc135 XL |
1005 | scope = self.declare_bindings( |
1006 | scope, | |
6a06907d | 1007 | expr.span, |
dc9dc135 XL |
1008 | &pattern, |
1009 | matches::ArmHasGuard(false), | |
1010 | Some((Some(&place), span)), | |
1011 | ); | |
6a06907d XL |
1012 | let place_builder = PlaceBuilder::from(local); |
1013 | unpack!( | |
1014 | block = self.place_into_pattern(block, pattern, place_builder, false) | |
1015 | ); | |
abe05a73 XL |
1016 | } |
1017 | } | |
416331ca | 1018 | self.source_scope = original_source_scope; |
a7813a04 | 1019 | } |
c30ab7b3 | 1020 | } |
a7813a04 | 1021 | |
94b46f34 XL |
1022 | // Enter the argument pattern bindings source scope, if it exists. |
1023 | if let Some(source_scope) = scope { | |
1024 | self.source_scope = source_scope; | |
3157f602 XL |
1025 | } |
1026 | ||
6a06907d | 1027 | self.expr_into_dest(Place::return_place(), block, &expr) |
416331ca XL |
1028 | } |
1029 | ||
1030 | fn set_correct_source_scope_for_arg( | |
1031 | &mut self, | |
1032 | arg_hir_id: hir::HirId, | |
1033 | original_source_scope: SourceScope, | |
dfeec247 | 1034 | pattern_span: Span, |
416331ca | 1035 | ) { |
6a06907d XL |
1036 | let tcx = self.tcx; |
1037 | let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id); | |
416331ca | 1038 | let parent_root = tcx.maybe_lint_level_root_bounded( |
60c5eb7d XL |
1039 | self.source_scopes[original_source_scope] |
1040 | .local_data | |
1041 | .as_ref() | |
1042 | .assert_crate_local() | |
1043 | .lint_root, | |
6a06907d | 1044 | self.hir_id, |
416331ca XL |
1045 | ); |
1046 | if current_root != parent_root { | |
dfeec247 XL |
1047 | self.source_scope = |
1048 | self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None); | |
416331ca | 1049 | } |
e9174d1e | 1050 | } |
7453a54e | 1051 | |
ff7c6d11 | 1052 | fn get_unit_temp(&mut self) -> Place<'tcx> { |
7453a54e | 1053 | match self.unit_temp { |
dfeec247 | 1054 | Some(tmp) => tmp, |
7453a54e | 1055 | None => { |
6a06907d | 1056 | let ty = self.tcx.mk_unit(); |
cc61c64b XL |
1057 | let fn_span = self.fn_span; |
1058 | let tmp = self.temp(ty, fn_span); | |
dfeec247 | 1059 | self.unit_temp = Some(tmp); |
7453a54e SL |
1060 | tmp |
1061 | } | |
1062 | } | |
1063 | } | |
e9174d1e SL |
1064 | } |
1065 | ||
1066 | /////////////////////////////////////////////////////////////////////////// | |
1067 | // Builder methods are broken up into modules, depending on what kind | |
94b46f34 | 1068 | // of thing is being lowered. Note that they use the `unpack` macro |
e9174d1e SL |
1069 | // above extensively. |
1070 | ||
1071 | mod block; | |
1072 | mod cfg; | |
1073 | mod expr; | |
e9174d1e SL |
1074 | mod matches; |
1075 | mod misc; | |
1076 | mod scope; |