]>
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 | ||
cdc7bbd5 XL |
255 | let bound_vars = |
256 | tcx.mk_bound_variable_kinds(std::iter::once(ty::BoundVariableKind::Region(ty::BrEnv))); | |
257 | let br = | |
258 | ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv }; | |
259 | let env_region = ty::ReLateBound(ty::INNERMOST, br); | |
260 | let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); | |
261 | tcx.erase_late_bound_regions(ty::Binder::bind_with_vars(closure_env_ty, bound_vars)) | |
7cac9316 | 262 | } |
b039eaaf | 263 | |
0bf4aa26 | 264 | #[derive(Debug, PartialEq, Eq)] |
dfeec247 | 265 | enum BlockFrame { |
0bf4aa26 XL |
266 | /// Evaluation is currently within a statement. |
267 | /// | |
268 | /// Examples include: | |
dc9dc135 XL |
269 | /// 1. `EXPR;` |
270 | /// 2. `let _ = EXPR;` | |
271 | /// 3. `let x = EXPR;` | |
0bf4aa26 XL |
272 | Statement { |
273 | /// If true, then statement discards result from evaluating | |
274 | /// the expression (such as examples 1 and 2 above). | |
dfeec247 | 275 | ignores_expr_result: bool, |
0bf4aa26 XL |
276 | }, |
277 | ||
278 | /// Evaluation is currently within the tail expression of a block. | |
279 | /// | |
280 | /// Example: `{ STMT_1; STMT_2; EXPR }` | |
281 | TailExpr { | |
282 | /// If true, then the surrounding context of the block ignores | |
283 | /// the result of evaluating the block's tail expression. | |
284 | /// | |
285 | /// Example: `let _ = { STMT_1; EXPR };` | |
dfeec247 | 286 | tail_result_is_ignored: bool, |
f9f354fc XL |
287 | |
288 | /// `Span` of the tail expression. | |
289 | span: Span, | |
0bf4aa26 XL |
290 | }, |
291 | ||
292 | /// Generic mark meaning that the block occurred as a subexpression | |
293 | /// where the result might be used. | |
294 | /// | |
295 | /// Examples: `foo(EXPR)`, `match EXPR { ... }` | |
296 | SubExpr, | |
297 | } | |
298 | ||
299 | impl BlockFrame { | |
300 | fn is_tail_expr(&self) -> bool { | |
301 | match *self { | |
302 | BlockFrame::TailExpr { .. } => true, | |
303 | ||
dfeec247 | 304 | BlockFrame::Statement { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
305 | } |
306 | } | |
307 | fn is_statement(&self) -> bool { | |
308 | match *self { | |
309 | BlockFrame::Statement { .. } => true, | |
310 | ||
dfeec247 | 311 | BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
312 | } |
313 | } | |
dfeec247 | 314 | } |
0bf4aa26 | 315 | |
a1dfa0c6 XL |
316 | #[derive(Debug)] |
317 | struct BlockContext(Vec<BlockFrame>); | |
318 | ||
dc9dc135 | 319 | struct Builder<'a, 'tcx> { |
6a06907d XL |
320 | tcx: TyCtxt<'tcx>, |
321 | infcx: &'a InferCtxt<'a, 'tcx>, | |
322 | typeck_results: &'tcx TypeckResults<'tcx>, | |
323 | region_scope_tree: &'tcx region::ScopeTree, | |
324 | param_env: ty::ParamEnv<'tcx>, | |
325 | ||
b039eaaf | 326 | cfg: CFG<'tcx>, |
54a0048b | 327 | |
29967ef6 | 328 | def_id: DefId, |
6a06907d XL |
329 | hir_id: hir::HirId, |
330 | check_overflow: bool, | |
54a0048b | 331 | fn_span: Span, |
c30ab7b3 | 332 | arg_count: usize, |
60c5eb7d | 333 | generator_kind: Option<GeneratorKind>, |
54a0048b | 334 | |
9fa01778 XL |
335 | /// The current set of scopes, updated as we traverse; |
336 | /// see the `scope` module for more details. | |
dc9dc135 | 337 | scopes: scope::Scopes<'tcx>, |
54a0048b | 338 | |
3dfed10e | 339 | /// The block-context: each time we build the code within an thir::Block, |
0bf4aa26 XL |
340 | /// we push a frame here tracking whether we are building a statement or |
341 | /// if we are pushing the tail expression of the block. This is used to | |
342 | /// embed information in generated temps about whether they were created | |
343 | /// for a block tail expression or not. | |
344 | /// | |
345 | /// It would be great if we could fold this into `self.scopes` | |
9fa01778 | 346 | /// somehow, but right now I think that is very tightly tied to |
0bf4aa26 XL |
347 | /// the code generation in ways that we cannot (or should not) |
348 | /// start just throwing new entries onto that vector in order to | |
349 | /// distinguish the context of EXPR1 from the context of EXPR2 in | |
9fa01778 | 350 | /// `{ STMTS; EXPR1 } + EXPR2`. |
a1dfa0c6 | 351 | block_context: BlockContext, |
0bf4aa26 | 352 | |
ea8adc8c | 353 | /// The current unsafe block in scope, even if it is hidden by |
9fa01778 | 354 | /// a `PushUnsafeBlock`. |
ea8adc8c XL |
355 | unpushed_unsafe: Safety, |
356 | ||
9fa01778 | 357 | /// The number of `push_unsafe_block` levels in scope. |
ea8adc8c XL |
358 | push_unsafe_count: usize, |
359 | ||
9fa01778 XL |
360 | /// The vector of all scopes that we have created thus far; |
361 | /// we track this for debuginfo later. | |
29967ef6 | 362 | source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, |
94b46f34 | 363 | source_scope: SourceScope, |
54a0048b | 364 | |
9fa01778 | 365 | /// The guard-context: each time we build the guard expression for |
83c7162d XL |
366 | /// a match arm, we push onto this stack, and then pop when we |
367 | /// finish building it. | |
368 | guard_context: Vec<GuardFrame>, | |
369 | ||
532ac7d7 | 370 | /// Maps `HirId`s of variable bindings to the `Local`s created for them. |
83c7162d | 371 | /// (A match binding can have two locals; the 2nd is for the arm's guard.) |
532ac7d7 | 372 | var_indices: HirIdMap<LocalsForNode>, |
c30ab7b3 | 373 | local_decls: IndexVec<Local, LocalDecl<'tcx>>, |
0731742a | 374 | canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, |
48663c56 | 375 | upvar_mutbls: Vec<Mutability>, |
ff7c6d11 | 376 | unit_temp: Option<Place<'tcx>>, |
54a0048b | 377 | |
60c5eb7d | 378 | var_debug_info: Vec<VarDebugInfo<'tcx>>, |
e9174d1e SL |
379 | } |
380 | ||
dc9dc135 | 381 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
532ac7d7 | 382 | fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool { |
83c7162d XL |
383 | self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) |
384 | } | |
385 | ||
532ac7d7 | 386 | fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local { |
83c7162d XL |
387 | self.var_indices[&id].local_id(for_guard) |
388 | } | |
389 | } | |
390 | ||
a1dfa0c6 | 391 | impl BlockContext { |
dfeec247 XL |
392 | fn new() -> Self { |
393 | BlockContext(vec![]) | |
394 | } | |
395 | fn push(&mut self, bf: BlockFrame) { | |
396 | self.0.push(bf); | |
397 | } | |
398 | fn pop(&mut self) -> Option<BlockFrame> { | |
399 | self.0.pop() | |
400 | } | |
a1dfa0c6 | 401 | |
9fa01778 | 402 | /// Traverses the frames on the `BlockContext`, searching for either |
a1dfa0c6 XL |
403 | /// the first block-tail expression frame with no intervening |
404 | /// statement frame. | |
405 | /// | |
406 | /// Notably, this skips over `SubExpr` frames; this method is | |
407 | /// meant to be used in the context of understanding the | |
408 | /// relationship of a temp (created within some complicated | |
409 | /// expression) with its containing expression, and whether the | |
410 | /// value of that *containing expression* (not the temp!) is | |
411 | /// ignored. | |
412 | fn currently_in_block_tail(&self) -> Option<BlockTailInfo> { | |
413 | for bf in self.0.iter().rev() { | |
414 | match bf { | |
415 | BlockFrame::SubExpr => continue, | |
416 | BlockFrame::Statement { .. } => break, | |
f9f354fc XL |
417 | &BlockFrame::TailExpr { tail_result_is_ignored, span } => { |
418 | return Some(BlockTailInfo { tail_result_is_ignored, span }); | |
dfeec247 | 419 | } |
a1dfa0c6 XL |
420 | } |
421 | } | |
422 | ||
ba9703b0 | 423 | None |
a1dfa0c6 XL |
424 | } |
425 | ||
426 | /// Looks at the topmost frame on the BlockContext and reports | |
427 | /// whether its one that would discard a block tail result. | |
428 | /// | |
429 | /// Unlike `currently_within_ignored_tail_expression`, this does | |
430 | /// *not* skip over `SubExpr` frames: here, we want to know | |
431 | /// whether the block result itself is discarded. | |
432 | fn currently_ignores_tail_results(&self) -> bool { | |
433 | match self.0.last() { | |
434 | // no context: conservatively assume result is read | |
435 | None => false, | |
436 | ||
437 | // sub-expression: block result feeds into some computation | |
438 | Some(BlockFrame::SubExpr) => false, | |
439 | ||
440 | // otherwise: use accumulated is_ignored state. | |
ba9703b0 | 441 | Some( |
f9f354fc | 442 | BlockFrame::TailExpr { tail_result_is_ignored: ignored, .. } |
ba9703b0 XL |
443 | | BlockFrame::Statement { ignores_expr_result: ignored }, |
444 | ) => *ignored, | |
a1dfa0c6 XL |
445 | } |
446 | } | |
447 | } | |
448 | ||
83c7162d XL |
449 | #[derive(Debug)] |
450 | enum LocalsForNode { | |
532ac7d7 | 451 | /// In the usual case, a `HirId` for an identifier maps to at most |
9fa01778 | 452 | /// one `Local` declaration. |
83c7162d | 453 | One(Local), |
8faf50e0 XL |
454 | |
455 | /// The exceptional case is identifiers in a match arm's pattern | |
456 | /// that are referenced in a guard of that match arm. For these, | |
9fa01778 | 457 | /// we have `2` Locals. |
8faf50e0 XL |
458 | /// |
459 | /// * `for_arm_body` is the Local used in the arm body (which is | |
460 | /// just like the `One` case above), | |
461 | /// | |
462 | /// * `ref_for_guard` is the Local used in the arm's guard (which | |
463 | /// is a reference to a temp that is an alias of | |
464 | /// `for_arm_body`). | |
9fa01778 | 465 | ForGuard { ref_for_guard: Local, for_arm_body: Local }, |
83c7162d XL |
466 | } |
467 | ||
468 | #[derive(Debug)] | |
469 | struct GuardFrameLocal { | |
532ac7d7 | 470 | id: hir::HirId, |
83c7162d XL |
471 | } |
472 | ||
473 | impl GuardFrameLocal { | |
532ac7d7 | 474 | fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self { |
74b04a01 | 475 | GuardFrameLocal { id } |
83c7162d XL |
476 | } |
477 | } | |
478 | ||
479 | #[derive(Debug)] | |
480 | struct GuardFrame { | |
481 | /// These are the id's of names that are bound by patterns of the | |
482 | /// arm of *this* guard. | |
483 | /// | |
484 | /// (Frames higher up the stack will have the id's bound in arms | |
485 | /// further out, such as in a case like: | |
486 | /// | |
487 | /// match E1 { | |
488 | /// P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1, | |
489 | /// } | |
490 | /// | |
9fa01778 | 491 | /// here, when building for FIXME. |
83c7162d XL |
492 | locals: Vec<GuardFrameLocal>, |
493 | } | |
494 | ||
9fa01778 XL |
495 | /// `ForGuard` indicates whether we are talking about: |
496 | /// 1. The variable for use outside of guard expressions, or | |
497 | /// 2. The temp that holds reference to (1.), which is actually what the | |
498 | /// guard expressions see. | |
83c7162d XL |
499 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
500 | enum ForGuard { | |
94b46f34 | 501 | RefWithinGuard, |
83c7162d XL |
502 | OutsideGuard, |
503 | } | |
504 | ||
505 | impl LocalsForNode { | |
506 | fn local_id(&self, for_guard: ForGuard) -> Local { | |
507 | match (self, for_guard) { | |
dfeec247 XL |
508 | (&LocalsForNode::One(local_id), ForGuard::OutsideGuard) |
509 | | ( | |
510 | &LocalsForNode::ForGuard { ref_for_guard: local_id, .. }, | |
511 | ForGuard::RefWithinGuard, | |
512 | ) | |
513 | | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => { | |
514 | local_id | |
515 | } | |
83c7162d | 516 | |
dfeec247 XL |
517 | (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => { |
518 | bug!("anything with one local should never be within a guard.") | |
519 | } | |
83c7162d XL |
520 | } |
521 | } | |
522 | } | |
523 | ||
b039eaaf | 524 | struct CFG<'tcx> { |
3157f602 XL |
525 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
526 | } | |
527 | ||
e74abb32 | 528 | rustc_index::newtype_index! { |
dfeec247 | 529 | struct ScopeId { .. } |
b7449926 | 530 | } |
e9174d1e SL |
531 | |
532 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
533 | /// The `BlockAnd` "monad" packages up the new basic block along with a |
534 | /// produced value (sometimes just unit, of course). The `unpack!` | |
535 | /// macro (and methods below) makes working with `BlockAnd` much more | |
536 | /// convenient. | |
e9174d1e | 537 | |
83c7162d | 538 | #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] |
7cac9316 | 539 | struct BlockAnd<T>(BasicBlock, T); |
e9174d1e | 540 | |
92a42be0 SL |
541 | trait BlockAndExtension { |
542 | fn and<T>(self, v: T) -> BlockAnd<T>; | |
543 | fn unit(self) -> BlockAnd<()>; | |
544 | } | |
545 | ||
546 | impl BlockAndExtension for BasicBlock { | |
e9174d1e SL |
547 | fn and<T>(self, v: T) -> BlockAnd<T> { |
548 | BlockAnd(self, v) | |
549 | } | |
550 | ||
551 | fn unit(self) -> BlockAnd<()> { | |
552 | BlockAnd(self, ()) | |
553 | } | |
554 | } | |
555 | ||
556 | /// Update a block pointer and return the value. | |
557 | /// Use it like `let x = unpack!(block = self.foo(block, foo))`. | |
558 | macro_rules! unpack { | |
dfeec247 XL |
559 | ($x:ident = $c:expr) => {{ |
560 | let BlockAnd(b, v) = $c; | |
561 | $x = b; | |
562 | v | |
563 | }}; | |
564 | ||
565 | ($c:expr) => {{ | |
566 | let BlockAnd(b, ()) = $c; | |
567 | b | |
568 | }}; | |
e9174d1e SL |
569 | } |
570 | ||
6a06907d | 571 | fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool { |
e74abb32 | 572 | // Validate `#[unwind]` syntax regardless of platform-specific panic strategy. |
f9f354fc | 573 | let attrs = &tcx.get_attrs(fn_def_id.to_def_id()); |
3dfed10e | 574 | let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs); |
532ac7d7 | 575 | |
e74abb32 | 576 | // We never unwind, so it's not relevant to stop an unwind. |
dfeec247 XL |
577 | if tcx.sess.panic_strategy() != PanicStrategy::Unwind { |
578 | return false; | |
579 | } | |
ff7c6d11 | 580 | |
532ac7d7 | 581 | match unwind_attr { |
6a06907d | 582 | // If an `#[unwind]` attribute was found, we should adhere to it. |
0531ce1d XL |
583 | Some(UnwindAttr::Allowed) => false, |
584 | Some(UnwindAttr::Aborts) => true, | |
6a06907d XL |
585 | // If no attribute was found and the panic strategy is `unwind`, then we should examine |
586 | // the function's ABI string to determine whether it should abort upon panic. | |
36d6ef2b | 587 | None if tcx.features().c_unwind => { |
6a06907d XL |
588 | use Abi::*; |
589 | match abi { | |
590 | // In the case of ABI's that have an `-unwind` equivalent, check whether the ABI | |
591 | // permits unwinding. If so, we should not abort. Otherwise, we should. | |
592 | C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { | |
593 | !unwind | |
594 | } | |
595 | // Rust and `rust-call` functions are allowed to unwind, and should not abort. | |
596 | Rust | RustCall => false, | |
597 | // Other ABI's should abort. | |
598 | Cdecl | |
599 | | Fastcall | |
600 | | Vectorcall | |
601 | | Aapcs | |
602 | | Win64 | |
603 | | SysV64 | |
604 | | PtxKernel | |
605 | | Msp430Interrupt | |
606 | | X86Interrupt | |
607 | | AmdGpuKernel | |
608 | | EfiApi | |
609 | | AvrInterrupt | |
610 | | AvrNonBlockingInterrupt | |
611 | | CCmseNonSecureCall | |
cdc7bbd5 | 612 | | Wasm |
6a06907d XL |
613 | | RustIntrinsic |
614 | | PlatformIntrinsic | |
615 | | Unadjusted => true, | |
616 | } | |
617 | } | |
36d6ef2b XL |
618 | // If the `c_unwind` feature gate is not active, follow the behavior that was in place |
619 | // prior to #76570. This is a special case: some functions have a C ABI but are meant to | |
620 | // unwind anyway. Don't stop them. | |
621 | None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)` | |
0531ce1d | 622 | } |
ff7c6d11 XL |
623 | } |
624 | ||
e9174d1e | 625 | /////////////////////////////////////////////////////////////////////////// |
7453a54e | 626 | /// the main entry point for building MIR for a function |
e9174d1e | 627 | |
dfeec247 XL |
628 | struct ArgInfo<'tcx>( |
629 | Ty<'tcx>, | |
630 | Option<Span>, | |
631 | Option<&'tcx hir::Param<'tcx>>, | |
632 | Option<ImplicitSelfKind>, | |
633 | ); | |
dc9dc135 | 634 | |
6a06907d XL |
635 | fn construct_fn<'tcx, A>( |
636 | infcx: &InferCtxt<'_, 'tcx>, | |
637 | fn_def: ty::WithOptConstParam<LocalDefId>, | |
dc9dc135 XL |
638 | fn_id: hir::HirId, |
639 | arguments: A, | |
640 | safety: Safety, | |
641 | abi: Abi, | |
642 | return_ty: Ty<'tcx>, | |
dc9dc135 | 643 | return_ty_span: Span, |
dfeec247 | 644 | body: &'tcx hir::Body<'tcx>, |
6a06907d | 645 | expr: &Expr<'_, 'tcx>, |
fc512014 | 646 | span_with_body: Span, |
dc9dc135 XL |
647 | ) -> Body<'tcx> |
648 | where | |
dfeec247 | 649 | A: Iterator<Item = ArgInfo<'tcx>>, |
a7813a04 | 650 | { |
c30ab7b3 SL |
651 | let arguments: Vec<_> = arguments.collect(); |
652 | ||
6a06907d XL |
653 | let tcx = infcx.tcx; |
654 | let span = tcx.hir().span(fn_id); | |
8faf50e0 | 655 | |
dfeec247 | 656 | let mut builder = Builder::new( |
6a06907d XL |
657 | infcx, |
658 | fn_def, | |
659 | fn_id, | |
3dfed10e | 660 | span_with_body, |
ea8adc8c XL |
661 | arguments.len(), |
662 | safety, | |
8faf50e0 | 663 | return_ty, |
0bf4aa26 | 664 | return_ty_span, |
dfeec247 XL |
665 | body.generator_kind, |
666 | ); | |
ea8adc8c | 667 | |
dfeec247 XL |
668 | let call_site_scope = |
669 | region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite }; | |
670 | let arg_scope = | |
671 | region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments }; | |
041b39d2 | 672 | let source_info = builder.source_info(span); |
ea8adc8c | 673 | let call_site_s = (call_site_scope, source_info); |
29967ef6 XL |
674 | unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { |
675 | let arg_scope_s = (arg_scope, source_info); | |
676 | // Attribute epilogue to function's closing brace | |
677 | let fn_end = span_with_body.shrink_to_hi(); | |
678 | let return_block = | |
679 | unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { | |
680 | Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { | |
681 | builder.args_and_body( | |
682 | START_BLOCK, | |
6a06907d | 683 | fn_def.did.to_def_id(), |
29967ef6 XL |
684 | &arguments, |
685 | arg_scope, | |
6a06907d | 686 | expr, |
29967ef6 XL |
687 | ) |
688 | })) | |
689 | })); | |
690 | let source_info = builder.source_info(fn_end); | |
691 | builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); | |
6a06907d | 692 | let should_abort = should_abort_on_panic(tcx, fn_def.did, abi); |
29967ef6 XL |
693 | builder.build_drop_trees(should_abort); |
694 | return_block.unit() | |
695 | })); | |
a7813a04 | 696 | |
ba9703b0 | 697 | let spread_arg = if abi == Abi::RustCall { |
476ff2be | 698 | // RustCall pseudo-ABI untuples the last argument. |
ba9703b0 XL |
699 | Some(Local::new(arguments.len())) |
700 | } else { | |
701 | None | |
702 | }; | |
6a06907d | 703 | debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id())); |
54a0048b | 704 | |
60c5eb7d | 705 | let mut body = builder.finish(); |
dc9dc135 XL |
706 | body.spread_arg = spread_arg; |
707 | body | |
a7813a04 XL |
708 | } |
709 | ||
dc9dc135 | 710 | fn construct_const<'a, 'tcx>( |
6a06907d XL |
711 | infcx: &'a InferCtxt<'a, 'tcx>, |
712 | expr: &Expr<'_, 'tcx>, | |
713 | def: ty::WithOptConstParam<LocalDefId>, | |
714 | hir_id: hir::HirId, | |
48663c56 XL |
715 | const_ty: Ty<'tcx>, |
716 | const_ty_span: Span, | |
dc9dc135 | 717 | ) -> Body<'tcx> { |
6a06907d XL |
718 | let tcx = infcx.tcx; |
719 | let span = tcx.hir().span(hir_id); | |
fc512014 | 720 | let mut builder = |
6a06907d | 721 | Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None); |
a7813a04 | 722 | |
a7813a04 | 723 | let mut block = START_BLOCK; |
6a06907d | 724 | unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr)); |
a7813a04 | 725 | |
7cac9316 XL |
726 | let source_info = builder.source_info(span); |
727 | builder.cfg.terminate(block, source_info, TerminatorKind::Return); | |
a7813a04 | 728 | |
29967ef6 | 729 | builder.build_drop_trees(false); |
ff7c6d11 | 730 | |
60c5eb7d | 731 | builder.finish() |
e9174d1e SL |
732 | } |
733 | ||
74b04a01 XL |
734 | /// Construct MIR for a item that has had errors in type checking. |
735 | /// | |
736 | /// This is required because we may still want to run MIR passes on an item | |
737 | /// with type errors, but normal MIR construction can't handle that in general. | |
6a06907d XL |
738 | fn construct_error<'a, 'tcx>( |
739 | infcx: &'a InferCtxt<'a, 'tcx>, | |
740 | def: ty::WithOptConstParam<LocalDefId>, | |
741 | hir_id: hir::HirId, | |
742 | body_id: hir::BodyId, | |
743 | body_owner_kind: hir::BodyOwnerKind, | |
744 | ) -> Body<'tcx> { | |
745 | let tcx = infcx.tcx; | |
746 | let span = tcx.hir().span(hir_id); | |
f035d41b | 747 | let ty = tcx.ty_error(); |
6a06907d XL |
748 | let generator_kind = tcx.hir().body(body_id).generator_kind; |
749 | let num_params = match body_owner_kind { | |
750 | hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len(), | |
74b04a01 | 751 | hir::BodyOwnerKind::Closure => { |
6a06907d | 752 | if generator_kind.is_some() { |
74b04a01 XL |
753 | // Generators have an implicit `self` parameter *and* a possibly |
754 | // implicit resume parameter. | |
755 | 2 | |
756 | } else { | |
757 | // The implicit self parameter adds another local in MIR. | |
6a06907d | 758 | 1 + tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len() |
74b04a01 XL |
759 | } |
760 | } | |
761 | hir::BodyOwnerKind::Const => 0, | |
762 | hir::BodyOwnerKind::Static(_) => 0, | |
763 | }; | |
fc512014 | 764 | let mut builder = |
6a06907d | 765 | Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind); |
8bb4bdeb | 766 | let source_info = builder.source_info(span); |
74b04a01 XL |
767 | // Some MIR passes will expect the number of parameters to match the |
768 | // function declaration. | |
769 | for _ in 0..num_params { | |
f9f354fc | 770 | builder.local_decls.push(LocalDecl::with_source_info(ty, source_info)); |
74b04a01 | 771 | } |
8bb4bdeb | 772 | builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); |
74b04a01 | 773 | let mut body = builder.finish(); |
6a06907d | 774 | body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty)); |
74b04a01 | 775 | body |
8bb4bdeb XL |
776 | } |
777 | ||
dc9dc135 | 778 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
dfeec247 | 779 | fn new( |
6a06907d XL |
780 | infcx: &'a InferCtxt<'a, 'tcx>, |
781 | def: ty::WithOptConstParam<LocalDefId>, | |
782 | hir_id: hir::HirId, | |
dfeec247 XL |
783 | span: Span, |
784 | arg_count: usize, | |
785 | safety: Safety, | |
786 | return_ty: Ty<'tcx>, | |
787 | return_span: Span, | |
788 | generator_kind: Option<GeneratorKind>, | |
789 | ) -> Builder<'a, 'tcx> { | |
6a06907d XL |
790 | let tcx = infcx.tcx; |
791 | let attrs = tcx.hir().attrs(hir_id); | |
792 | // Some functions always have overflow checks enabled, | |
793 | // however, they may not get codegen'd, depending on | |
794 | // the settings for the crate they are codegened in. | |
795 | let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); | |
796 | // Respect -C overflow-checks. | |
797 | check_overflow |= tcx.sess.overflow_checks(); | |
798 | // Constants always need overflow checks. | |
799 | check_overflow |= matches!( | |
800 | tcx.hir().body_owner_kind(hir_id), | |
801 | hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) | |
802 | ); | |
803 | ||
804 | let lint_level = LintLevel::Explicit(hir_id); | |
a7813a04 | 805 | let mut builder = Builder { |
6a06907d XL |
806 | tcx, |
807 | infcx, | |
808 | typeck_results: tcx.typeck_opt_const_arg(def), | |
809 | region_scope_tree: tcx.region_scope_tree(def.did), | |
810 | param_env: tcx.param_env(def.did), | |
811 | def_id: def.did.to_def_id(), | |
812 | hir_id, | |
813 | check_overflow, | |
3157f602 | 814 | cfg: CFG { basic_blocks: IndexVec::new() }, |
a7813a04 | 815 | fn_span: span, |
3b2f2976 | 816 | arg_count, |
60c5eb7d | 817 | generator_kind, |
29967ef6 | 818 | scopes: scope::Scopes::new(), |
a1dfa0c6 | 819 | block_context: BlockContext::new(), |
94b46f34 XL |
820 | source_scopes: IndexVec::new(), |
821 | source_scope: OUTERMOST_SOURCE_SCOPE, | |
83c7162d | 822 | guard_context: vec![], |
ea8adc8c XL |
823 | push_unsafe_count: 0, |
824 | unpushed_unsafe: safety, | |
f9f354fc | 825 | local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), |
0731742a | 826 | canonical_user_type_annotations: IndexVec::new(), |
60c5eb7d | 827 | upvar_mutbls: vec![], |
a1dfa0c6 | 828 | var_indices: Default::default(), |
a7813a04 | 829 | unit_temp: None, |
60c5eb7d | 830 | var_debug_info: vec![], |
a7813a04 XL |
831 | }; |
832 | ||
833 | assert_eq!(builder.cfg.start_new_block(), START_BLOCK); | |
ea8adc8c | 834 | assert_eq!( |
94b46f34 | 835 | builder.new_source_scope(span, lint_level, Some(safety)), |
dfeec247 XL |
836 | OUTERMOST_SOURCE_SCOPE |
837 | ); | |
94b46f34 | 838 | builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None; |
a7813a04 XL |
839 | |
840 | builder | |
841 | } | |
842 | ||
60c5eb7d | 843 | fn finish(self) -> Body<'tcx> { |
a7813a04 XL |
844 | for (index, block) in self.cfg.basic_blocks.iter().enumerate() { |
845 | if block.terminator.is_none() { | |
846 | span_bug!(self.fn_span, "no terminator on block {:?}", index); | |
847 | } | |
848 | } | |
849 | ||
dc9dc135 | 850 | Body::new( |
29967ef6 | 851 | MirSource::item(self.def_id), |
0731742a XL |
852 | self.cfg.basic_blocks, |
853 | self.source_scopes, | |
0731742a XL |
854 | self.local_decls, |
855 | self.canonical_user_type_annotations, | |
856 | self.arg_count, | |
60c5eb7d | 857 | self.var_debug_info, |
0731742a | 858 | self.fn_span, |
dfeec247 | 859 | self.generator_kind, |
476ff2be | 860 | ) |
a7813a04 XL |
861 | } |
862 | ||
dfeec247 XL |
863 | fn args_and_body( |
864 | &mut self, | |
865 | mut block: BasicBlock, | |
866 | fn_def_id: DefId, | |
867 | arguments: &[ArgInfo<'tcx>], | |
868 | argument_scope: region::Scope, | |
6a06907d | 869 | expr: &Expr<'_, 'tcx>, |
dfeec247 | 870 | ) -> BlockAnd<()> { |
c30ab7b3 | 871 | // Allocate locals for the function arguments |
416331ca | 872 | for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { |
f9f354fc XL |
873 | let source_info = |
874 | SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span)); | |
875 | let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info)); | |
60c5eb7d XL |
876 | |
877 | // If this is a simple binding pattern, give debuginfo a nice name. | |
878 | if let Some(arg) = arg_opt { | |
879 | if let Some(ident) = arg.pat.simple_ident() { | |
880 | self.var_debug_info.push(VarDebugInfo { | |
881 | name: ident.name, | |
882 | source_info, | |
fc512014 | 883 | value: VarDebugInfoContents::Place(arg_local.into()), |
60c5eb7d XL |
884 | }); |
885 | } | |
886 | } | |
887 | } | |
888 | ||
6a06907d | 889 | let tcx = self.tcx; |
60c5eb7d | 890 | let tcx_hir = tcx.hir(); |
6a06907d | 891 | let hir_typeck_results = self.typeck_results; |
60c5eb7d XL |
892 | |
893 | // In analyze_closure() in upvar.rs we gathered a list of upvars used by a | |
6a06907d | 894 | // indexed closure and we stored in a map called closure_min_captures in TypeckResults |
60c5eb7d XL |
895 | // with the closure's DefId. Here, we run through that vec of UpvarIds for |
896 | // the given closure and use the necessary information to create upvar | |
897 | // debuginfo and to fill `self.upvar_mutbls`. | |
fc512014 | 898 | if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { |
60c5eb7d XL |
899 | let closure_env_arg = Local::new(1); |
900 | let mut closure_env_projs = vec![]; | |
901 | let mut closure_ty = self.local_decls[closure_env_arg].ty; | |
1b1a35ee | 902 | if let ty::Ref(_, ty, _) = closure_ty.kind() { |
60c5eb7d XL |
903 | closure_env_projs.push(ProjectionElem::Deref); |
904 | closure_ty = ty; | |
905 | } | |
1b1a35ee | 906 | let upvar_substs = match closure_ty.kind() { |
ba9703b0 XL |
907 | ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), |
908 | ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), | |
dfeec247 | 909 | _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), |
60c5eb7d | 910 | }; |
fc512014 | 911 | let capture_tys = upvar_substs.upvar_tys(); |
5869c6ff XL |
912 | let captures_with_tys = |
913 | hir_typeck_results.closure_min_captures_flattened(fn_def_id).zip(capture_tys); | |
fc512014 XL |
914 | |
915 | self.upvar_mutbls = captures_with_tys | |
dfeec247 | 916 | .enumerate() |
fc512014 XL |
917 | .map(|(i, (captured_place, ty))| { |
918 | let capture = captured_place.info.capture_kind; | |
919 | let var_id = match captured_place.place.base { | |
920 | HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, | |
5869c6ff | 921 | _ => bug!("Expected an upvar"), |
fc512014 | 922 | }; |
dfeec247 | 923 | |
5869c6ff | 924 | let mutability = captured_place.mutability; |
fc512014 XL |
925 | |
926 | // FIXME(project-rfc-2229#8): Store more precise information | |
5869c6ff | 927 | let mut name = kw::Empty; |
dfeec247 XL |
928 | if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { |
929 | if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { | |
930 | name = ident.name; | |
60c5eb7d XL |
931 | } |
932 | } | |
60c5eb7d | 933 | |
dfeec247 XL |
934 | let mut projs = closure_env_projs.clone(); |
935 | projs.push(ProjectionElem::Field(Field::new(i), ty)); | |
936 | match capture { | |
1b1a35ee | 937 | ty::UpvarCapture::ByValue(_) => {} |
dfeec247 XL |
938 | ty::UpvarCapture::ByRef(..) => { |
939 | projs.push(ProjectionElem::Deref); | |
940 | } | |
941 | }; | |
60c5eb7d | 942 | |
dfeec247 XL |
943 | self.var_debug_info.push(VarDebugInfo { |
944 | name, | |
f9f354fc | 945 | source_info: SourceInfo::outermost(tcx_hir.span(var_id)), |
fc512014 | 946 | value: VarDebugInfoContents::Place(Place { |
74b04a01 | 947 | local: closure_env_arg, |
dfeec247 | 948 | projection: tcx.intern_place_elems(&projs), |
fc512014 | 949 | }), |
dfeec247 | 950 | }); |
60c5eb7d | 951 | |
dfeec247 XL |
952 | mutability |
953 | }) | |
954 | .collect(); | |
c30ab7b3 SL |
955 | } |
956 | ||
3157f602 | 957 | let mut scope = None; |
c30ab7b3 | 958 | // Bind the argument patterns |
94b46f34 | 959 | for (index, arg_info) in arguments.iter().enumerate() { |
ff7c6d11 | 960 | // Function arguments always get the first Local indices after the return place |
abe05a73 | 961 | let local = Local::new(index + 1); |
dc9dc135 | 962 | let place = Place::from(local); |
e74abb32 | 963 | let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info; |
c30ab7b3 | 964 | |
0731742a XL |
965 | // Make sure we drop (parts of) the argument even when not matched on. |
966 | self.schedule_drop( | |
6a06907d | 967 | arg_opt.as_ref().map_or(expr.span, |arg| arg.pat.span), |
dfeec247 XL |
968 | argument_scope, |
969 | local, | |
970 | DropKind::Value, | |
0731742a XL |
971 | ); |
972 | ||
416331ca | 973 | if let Some(arg) = arg_opt { |
6a06907d XL |
974 | let pat = match tcx.hir().get(arg.pat.hir_id) { |
975 | Node::Pat(pat) | Node::Binding(pat) => pat, | |
976 | node => bug!("pattern became {:?}", node), | |
977 | }; | |
978 | let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat); | |
416331ca | 979 | let original_source_scope = self.source_scope; |
8faf50e0 | 980 | let span = pattern.span; |
416331ca | 981 | self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); |
abe05a73 XL |
982 | match *pattern.kind { |
983 | // Don't introduce extra copies for simple bindings | |
e74abb32 | 984 | PatKind::Binding { |
dc9dc135 XL |
985 | mutability, |
986 | var, | |
987 | mode: BindingMode::ByValue, | |
988 | subpattern: None, | |
989 | .. | |
990 | } => { | |
abe05a73 | 991 | self.local_decls[local].mutability = mutability; |
416331ca | 992 | self.local_decls[local].source_info.scope = self.source_scope; |
dfeec247 | 993 | self.local_decls[local].local_info = if let Some(kind) = self_binding { |
f035d41b XL |
994 | Some(box LocalInfo::User(ClearCrossCrate::Set( |
995 | BindingForm::ImplicitSelf(*kind), | |
996 | ))) | |
dfeec247 | 997 | } else { |
74b04a01 | 998 | let binding_mode = ty::BindingMode::BindByValue(mutability); |
f9f354fc | 999 | Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( |
dfeec247 XL |
1000 | VarBindingForm { |
1001 | binding_mode, | |
1002 | opt_ty_info, | |
1003 | opt_match_place: Some((Some(place), span)), | |
1004 | pat_span: span, | |
1005 | }, | |
f9f354fc | 1006 | )))) |
dfeec247 | 1007 | }; |
83c7162d | 1008 | self.var_indices.insert(var, LocalsForNode::One(local)); |
abe05a73 XL |
1009 | } |
1010 | _ => { | |
dc9dc135 XL |
1011 | scope = self.declare_bindings( |
1012 | scope, | |
6a06907d | 1013 | expr.span, |
dc9dc135 XL |
1014 | &pattern, |
1015 | matches::ArmHasGuard(false), | |
1016 | Some((Some(&place), span)), | |
1017 | ); | |
6a06907d XL |
1018 | let place_builder = PlaceBuilder::from(local); |
1019 | unpack!( | |
1020 | block = self.place_into_pattern(block, pattern, place_builder, false) | |
1021 | ); | |
abe05a73 XL |
1022 | } |
1023 | } | |
416331ca | 1024 | self.source_scope = original_source_scope; |
a7813a04 | 1025 | } |
c30ab7b3 | 1026 | } |
a7813a04 | 1027 | |
94b46f34 XL |
1028 | // Enter the argument pattern bindings source scope, if it exists. |
1029 | if let Some(source_scope) = scope { | |
1030 | self.source_scope = source_scope; | |
3157f602 XL |
1031 | } |
1032 | ||
6a06907d | 1033 | self.expr_into_dest(Place::return_place(), block, &expr) |
416331ca XL |
1034 | } |
1035 | ||
1036 | fn set_correct_source_scope_for_arg( | |
1037 | &mut self, | |
1038 | arg_hir_id: hir::HirId, | |
1039 | original_source_scope: SourceScope, | |
dfeec247 | 1040 | pattern_span: Span, |
416331ca | 1041 | ) { |
6a06907d XL |
1042 | let tcx = self.tcx; |
1043 | let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id); | |
416331ca | 1044 | let parent_root = tcx.maybe_lint_level_root_bounded( |
60c5eb7d XL |
1045 | self.source_scopes[original_source_scope] |
1046 | .local_data | |
1047 | .as_ref() | |
1048 | .assert_crate_local() | |
1049 | .lint_root, | |
6a06907d | 1050 | self.hir_id, |
416331ca XL |
1051 | ); |
1052 | if current_root != parent_root { | |
dfeec247 XL |
1053 | self.source_scope = |
1054 | self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None); | |
416331ca | 1055 | } |
e9174d1e | 1056 | } |
7453a54e | 1057 | |
ff7c6d11 | 1058 | fn get_unit_temp(&mut self) -> Place<'tcx> { |
7453a54e | 1059 | match self.unit_temp { |
dfeec247 | 1060 | Some(tmp) => tmp, |
7453a54e | 1061 | None => { |
6a06907d | 1062 | let ty = self.tcx.mk_unit(); |
cc61c64b XL |
1063 | let fn_span = self.fn_span; |
1064 | let tmp = self.temp(ty, fn_span); | |
dfeec247 | 1065 | self.unit_temp = Some(tmp); |
7453a54e SL |
1066 | tmp |
1067 | } | |
1068 | } | |
1069 | } | |
e9174d1e SL |
1070 | } |
1071 | ||
1072 | /////////////////////////////////////////////////////////////////////////// | |
1073 | // Builder methods are broken up into modules, depending on what kind | |
94b46f34 | 1074 | // of thing is being lowered. Note that they use the `unpack` macro |
e9174d1e SL |
1075 | // above extensively. |
1076 | ||
1077 | mod block; | |
1078 | mod cfg; | |
1079 | mod expr; | |
e9174d1e SL |
1080 | mod matches; |
1081 | mod misc; | |
1082 | mod scope; |