1use itertools::Itertools;
7use rustc_abi::{ExternAbi, FieldIdx};
8use rustc_apfloat::Float;
9use rustc_apfloat::ieee::{Double, Half, Quad, Single};
10use rustc_ast::attr;
11use rustc_data_structures::fx::FxHashMap;
12use rustc_data_structures::sorted_map::SortedIndexMultiMap;
13use rustc_errors::ErrorGuaranteed;
14use rustc_hir::def::DefKind;
15use rustc_hir::def_id::{DefId, LocalDefId};
16use rustc_hir::{self as hir, BindingMode, ByRef, HirId, ItemLocalId, Node};
17use rustc_index::bit_set::GrowableBitSet;
18use rustc_index::{Idx, IndexSlice, IndexVec};
19use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
20use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
21use rustc_middle::middle::region;
22use rustc_middle::mir::*;
23use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
24use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
25use rustc_middle::{bug, span_bug};
26use rustc_span::{Span, Symbol, sym};
27
28use crate::builder::expr::as_place::PlaceBuilder;
29use crate::builder::scope::DropKind;
30
31pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
32 tcx: TyCtxt<'tcx>,
33 def_id: LocalDefId,
34) -> IndexVec<FieldIdx, Symbol> {
35 tcx.closure_captures(def_id)
36 .iter()
37 .map(|captured_place| {
38 let name = captured_place.to_symbol();
39 match captured_place.info.capture_kind {
40 ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name,
41 ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")),
42 }
43 })
44 .collect()
45}
46
47pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
50 tcx.ensure_done().thir_abstract_const(def);
51 if let Err(e) = tcx.ensure_ok().check_match(def) {
52 return construct_error(tcx, def, e);
53 }
54
55 if let Err(err) = tcx.ensure_ok().check_tail_calls(def) {
56 return construct_error(tcx, def, err);
57 }
58
59 let body = match tcx.thir_body(def) {
60 Err(error_reported) => construct_error(tcx, def, error_reported),
61 Ok((thir, expr)) => {
62 let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
63 thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
64 thir::BodyTy::Const(ty) | thir::BodyTy::GlobalAsm(ty) => {
65 construct_const(tcx, def, thir, expr, ty)
66 }
67 };
68
69 tcx.ensure_ok().check_liveness(def);
73
74 build_mir(&thir.borrow())
78 }
79 };
80
81 debug_assert!(
86 !(body.local_decls.has_free_regions()
87 || body.basic_blocks.has_free_regions()
88 || body.var_debug_info.has_free_regions()
89 || body.yield_ty().has_free_regions()),
90 "Unexpected free regions in MIR: {body:?}",
91 );
92
93 body
94}
95
96#[derive(Debug, PartialEq, Eq)]
100enum BlockFrame {
101 Statement {
108 ignores_expr_result: bool,
111 },
112
113 TailExpr { info: BlockTailInfo },
117
118 SubExpr,
123}
124
125impl BlockFrame {
126 fn is_tail_expr(&self) -> bool {
127 match *self {
128 BlockFrame::TailExpr { .. } => true,
129
130 BlockFrame::Statement { .. } | BlockFrame::SubExpr => false,
131 }
132 }
133 fn is_statement(&self) -> bool {
134 match *self {
135 BlockFrame::Statement { .. } => true,
136
137 BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false,
138 }
139 }
140}
141
142#[derive(Debug)]
143struct BlockContext(Vec<BlockFrame>);
144
145struct Builder<'a, 'tcx> {
146 tcx: TyCtxt<'tcx>,
147 infcx: InferCtxt<'tcx>,
152 region_scope_tree: &'tcx region::ScopeTree,
153 param_env: ty::ParamEnv<'tcx>,
154
155 thir: &'a Thir<'tcx>,
156 cfg: CFG<'tcx>,
157
158 def_id: LocalDefId,
159 hir_id: HirId,
160 parent_module: DefId,
161 check_overflow: bool,
162 fn_span: Span,
163 arg_count: usize,
164 coroutine: Option<Box<CoroutineInfo<'tcx>>>,
165
166 scopes: scope::Scopes<'tcx>,
169
170 block_context: BlockContext,
183
184 source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
187 source_scope: SourceScope,
188
189 guard_context: Vec<GuardFrame>,
193
194 fixed_temps: FxHashMap<ExprId, Local>,
197 fixed_temps_scope: Option<region::Scope>,
199
200 var_indices: FxHashMap<LocalVarId, LocalsForNode>,
203 local_decls: IndexVec<Local, LocalDecl<'tcx>>,
204 canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
205 upvars: CaptureMap<'tcx>,
206 unit_temp: Option<Place<'tcx>>,
207
208 var_debug_info: Vec<VarDebugInfo<'tcx>>,
209
210 lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
217
218 coverage_info: Option<coverageinfo::CoverageInfoBuilder>,
221}
222
223type CaptureMap<'tcx> = SortedIndexMultiMap<usize, ItemLocalId, Capture<'tcx>>;
224
225#[derive(Debug)]
226struct Capture<'tcx> {
227 captured_place: &'tcx ty::CapturedPlace<'tcx>,
228 use_place: Place<'tcx>,
229 mutability: Mutability,
230}
231
232impl<'a, 'tcx> Builder<'a, 'tcx> {
233 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
234 self.infcx.typing_env(self.param_env)
235 }
236
237 fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
238 self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
239 }
240
241 fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local {
242 self.var_indices[&id].local_id(for_guard)
243 }
244}
245
246impl BlockContext {
247 fn new() -> Self {
248 BlockContext(vec![])
249 }
250 fn push(&mut self, bf: BlockFrame) {
251 self.0.push(bf);
252 }
253 fn pop(&mut self) -> Option<BlockFrame> {
254 self.0.pop()
255 }
256
257 fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
268 for bf in self.0.iter().rev() {
269 match bf {
270 BlockFrame::SubExpr => continue,
271 BlockFrame::Statement { .. } => break,
272 &BlockFrame::TailExpr { info } => return Some(info),
273 }
274 }
275
276 None
277 }
278
279 fn currently_ignores_tail_results(&self) -> bool {
286 match self.0.last() {
287 None => false,
289
290 Some(BlockFrame::SubExpr) => false,
292
293 Some(
295 BlockFrame::TailExpr { info: BlockTailInfo { tail_result_is_ignored: ign, .. } }
296 | BlockFrame::Statement { ignores_expr_result: ign },
297 ) => *ign,
298 }
299 }
300}
301
302#[derive(Debug)]
303enum LocalsForNode {
304 One(Local),
307
308 ForGuard { ref_for_guard: Local, for_arm_body: Local },
319}
320
321#[derive(Debug)]
322struct GuardFrameLocal {
323 id: LocalVarId,
324}
325
326impl GuardFrameLocal {
327 fn new(id: LocalVarId) -> Self {
328 GuardFrameLocal { id }
329 }
330}
331
332#[derive(Debug)]
333struct GuardFrame {
334 locals: Vec<GuardFrameLocal>,
346}
347
348#[derive(Copy, Clone, Debug, PartialEq, Eq)]
353enum ForGuard {
354 RefWithinGuard,
355 OutsideGuard,
356}
357
358impl LocalsForNode {
359 fn local_id(&self, for_guard: ForGuard) -> Local {
360 match (self, for_guard) {
361 (&LocalsForNode::One(local_id), ForGuard::OutsideGuard)
362 | (
363 &LocalsForNode::ForGuard { ref_for_guard: local_id, .. },
364 ForGuard::RefWithinGuard,
365 )
366 | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => {
367 local_id
368 }
369
370 (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => {
371 bug!("anything with one local should never be within a guard.")
372 }
373 }
374 }
375}
376
377struct CFG<'tcx> {
378 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
379}
380
381rustc_index::newtype_index! {
382 struct ScopeId {}
383}
384
385#[derive(Debug)]
386enum NeedsTemporary {
387 No,
392 Maybe,
395}
396
397#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
404struct BlockAnd<T>(BasicBlock, T);
405
406impl BlockAnd<()> {
407 #[must_use]
409 fn into_block(self) -> BasicBlock {
410 let Self(block, ()) = self;
411 block
412 }
413}
414
415trait BlockAndExtension {
416 fn and<T>(self, v: T) -> BlockAnd<T>;
417 fn unit(self) -> BlockAnd<()>;
418}
419
420impl BlockAndExtension for BasicBlock {
421 fn and<T>(self, v: T) -> BlockAnd<T> {
422 BlockAnd(self, v)
423 }
424
425 fn unit(self) -> BlockAnd<()> {
426 BlockAnd(self, ())
427 }
428}
429
430macro_rules! unpack {
433 ($x:ident = $c:expr) => {{
434 let BlockAnd(b, v) = $c;
435 $x = b;
436 v
437 }};
438}
439
440fn construct_fn<'tcx>(
444 tcx: TyCtxt<'tcx>,
445 fn_def: LocalDefId,
446 thir: &Thir<'tcx>,
447 expr: ExprId,
448 fn_sig: ty::FnSig<'tcx>,
449) -> Body<'tcx> {
450 let span = tcx.def_span(fn_def);
451 let fn_id = tcx.local_def_id_to_hir_id(fn_def);
452
453 let body = tcx.hir_body_owned_by(fn_def);
455 let span_with_body = tcx.hir_span_with_body(fn_id);
456 let return_ty_span = tcx
457 .hir_fn_decl_by_hir_id(fn_id)
458 .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def))
459 .output
460 .span();
461
462 let mut abi = fn_sig.abi;
463 if let DefKind::Closure = tcx.def_kind(fn_def) {
464 abi = ExternAbi::Rust;
467 }
468
469 let arguments = &thir.params;
470
471 let return_ty = fn_sig.output();
472 let coroutine = match tcx.type_of(fn_def).instantiate_identity().kind() {
473 ty::Coroutine(_, args) => Some(Box::new(CoroutineInfo::initial(
474 tcx.coroutine_kind(fn_def).unwrap(),
475 args.as_coroutine().yield_ty(),
476 args.as_coroutine().resume_ty(),
477 ))),
478 ty::Closure(..) | ty::CoroutineClosure(..) | ty::FnDef(..) => None,
479 ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"),
480 };
481
482 if let Some(custom_mir_attr) =
483 tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir))
484 {
485 return custom::build_custom_mir(
486 tcx,
487 fn_def.to_def_id(),
488 fn_id,
489 thir,
490 expr,
491 arguments,
492 return_ty,
493 return_ty_span,
494 span_with_body,
495 custom_mir_attr,
496 );
497 }
498
499 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
502 let mut builder = Builder::new(
503 thir,
504 infcx,
505 fn_def,
506 fn_id,
507 span_with_body,
508 arguments.len(),
509 return_ty,
510 return_ty_span,
511 coroutine,
512 );
513
514 let call_site_scope =
515 region::Scope { local_id: body.id().hir_id.local_id, data: region::ScopeData::CallSite };
516 let arg_scope =
517 region::Scope { local_id: body.id().hir_id.local_id, data: region::ScopeData::Arguments };
518 let source_info = builder.source_info(span);
519 let call_site_s = (call_site_scope, source_info);
520 let _: BlockAnd<()> = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
521 let arg_scope_s = (arg_scope, source_info);
522 let fn_end = span_with_body.shrink_to_hi();
524 let return_block = builder
525 .in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
526 Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
527 builder.args_and_body(START_BLOCK, arguments, arg_scope, expr)
528 }))
529 })
530 .into_block();
531 let source_info = builder.source_info(fn_end);
532 builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
533 builder.build_drop_trees();
534 return_block.unit()
535 });
536
537 let mut body = builder.finish();
538
539 body.spread_arg = if abi == ExternAbi::RustCall {
540 Some(Local::new(arguments.len()))
542 } else {
543 None
544 };
545
546 body
547}
548
549fn construct_const<'a, 'tcx>(
550 tcx: TyCtxt<'tcx>,
551 def: LocalDefId,
552 thir: &'a Thir<'tcx>,
553 expr: ExprId,
554 const_ty: Ty<'tcx>,
555) -> Body<'tcx> {
556 let hir_id = tcx.local_def_id_to_hir_id(def);
557
558 let (span, const_ty_span) = match tcx.hir_node(hir_id) {
560 Node::Item(hir::Item {
561 kind: hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _),
562 span,
563 ..
564 })
565 | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. })
566 | Node::TraitItem(hir::TraitItem {
567 kind: hir::TraitItemKind::Const(ty, Some(_)),
568 span,
569 ..
570 }) => (*span, ty.span),
571 Node::AnonConst(ct) => (ct.span, ct.span),
572 Node::ConstBlock(_) => {
573 let span = tcx.def_span(def);
574 (span, span)
575 }
576 Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, span, .. }) => (*span, *span),
577 _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
578 };
579
580 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
583 let mut builder =
584 Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
585
586 let mut block = START_BLOCK;
587 block = builder.expr_into_dest(Place::return_place(), block, expr).into_block();
588
589 let source_info = builder.source_info(span);
590 builder.cfg.terminate(block, source_info, TerminatorKind::Return);
591
592 builder.build_drop_trees();
593
594 builder.finish()
595}
596
597fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> {
602 let span = tcx.def_span(def_id);
603 let hir_id = tcx.local_def_id_to_hir_id(def_id);
604
605 let (inputs, output, coroutine) = match tcx.def_kind(def_id) {
606 DefKind::Const
607 | DefKind::AssocConst
608 | DefKind::AnonConst
609 | DefKind::InlineConst
610 | DefKind::Static { .. }
611 | DefKind::GlobalAsm => (vec![], tcx.type_of(def_id).instantiate_identity(), None),
612 DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => {
613 let sig = tcx.liberate_late_bound_regions(
614 def_id.to_def_id(),
615 tcx.fn_sig(def_id).instantiate_identity(),
616 );
617 (sig.inputs().to_vec(), sig.output(), None)
618 }
619 DefKind::Closure => {
620 let closure_ty = tcx.type_of(def_id).instantiate_identity();
621 match closure_ty.kind() {
622 ty::Closure(_, args) => {
623 let args = args.as_closure();
624 let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig());
625 let self_ty = match args.kind() {
626 ty::ClosureKind::Fn => {
627 Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty)
628 }
629 ty::ClosureKind::FnMut => {
630 Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty)
631 }
632 ty::ClosureKind::FnOnce => closure_ty,
633 };
634 (
635 [self_ty].into_iter().chain(sig.inputs()[0].tuple_fields()).collect(),
636 sig.output(),
637 None,
638 )
639 }
640 ty::Coroutine(_, args) => {
641 let args = args.as_coroutine();
642 let resume_ty = args.resume_ty();
643 let yield_ty = args.yield_ty();
644 let return_ty = args.return_ty();
645 (
646 vec![closure_ty, resume_ty],
647 return_ty,
648 Some(Box::new(CoroutineInfo::initial(
649 tcx.coroutine_kind(def_id).unwrap(),
650 yield_ty,
651 resume_ty,
652 ))),
653 )
654 }
655 ty::CoroutineClosure(did, args) => {
656 let args = args.as_coroutine_closure();
657 let sig = tcx.liberate_late_bound_regions(
658 def_id.to_def_id(),
659 args.coroutine_closure_sig(),
660 );
661 let self_ty = match args.kind() {
662 ty::ClosureKind::Fn => {
663 Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty)
664 }
665 ty::ClosureKind::FnMut => {
666 Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty)
667 }
668 ty::ClosureKind::FnOnce => closure_ty,
669 };
670 (
671 [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()).collect(),
672 sig.to_coroutine(
673 tcx,
674 args.parent_args(),
675 args.kind_ty(),
676 tcx.coroutine_for_closure(*did),
677 Ty::new_error(tcx, guar),
678 ),
679 None,
680 )
681 }
682 ty::Error(_) => (vec![closure_ty, closure_ty], closure_ty, None),
683 kind => {
684 span_bug!(
685 span,
686 "expected type of closure body to be a closure or coroutine, got {kind:?}"
687 );
688 }
689 }
690 }
691 dk => span_bug!(span, "{:?} is not a body: {:?}", def_id, dk),
692 };
693
694 let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
695 let local_decls = IndexVec::from_iter(
696 [output].iter().chain(&inputs).map(|ty| LocalDecl::with_source_info(*ty, source_info)),
697 );
698 let mut cfg = CFG { basic_blocks: IndexVec::new() };
699 let mut source_scopes = IndexVec::new();
700
701 cfg.start_new_block();
702 source_scopes.push(SourceScopeData {
703 span,
704 parent_scope: None,
705 inlined: None,
706 inlined_parent_scope: None,
707 local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
708 });
709
710 cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
711
712 Body::new(
713 MirSource::item(def_id.to_def_id()),
714 cfg.basic_blocks,
715 source_scopes,
716 local_decls,
717 IndexVec::new(),
718 inputs.len(),
719 vec![],
720 span,
721 coroutine,
722 Some(guar),
723 )
724}
725
726impl<'a, 'tcx> Builder<'a, 'tcx> {
727 fn new(
728 thir: &'a Thir<'tcx>,
729 infcx: InferCtxt<'tcx>,
730 def: LocalDefId,
731 hir_id: HirId,
732 span: Span,
733 arg_count: usize,
734 return_ty: Ty<'tcx>,
735 return_span: Span,
736 coroutine: Option<Box<CoroutineInfo<'tcx>>>,
737 ) -> Builder<'a, 'tcx> {
738 let tcx = infcx.tcx;
739 let attrs = tcx.hir_attrs(hir_id);
740 let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
744 check_overflow |= tcx.sess.overflow_checks();
746 check_overflow |= matches!(
748 tcx.hir_body_owner_kind(def),
749 hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
750 );
751
752 let lint_level = LintLevel::Explicit(hir_id);
753 let param_env = tcx.param_env(def);
754 let mut builder = Builder {
755 thir,
756 tcx,
757 infcx,
758 region_scope_tree: tcx.region_scope_tree(def),
759 param_env,
760 def_id: def,
761 hir_id,
762 parent_module: tcx.parent_module(hir_id).to_def_id(),
763 check_overflow,
764 cfg: CFG { basic_blocks: IndexVec::new() },
765 fn_span: span,
766 arg_count,
767 coroutine,
768 scopes: scope::Scopes::new(),
769 block_context: BlockContext::new(),
770 source_scopes: IndexVec::new(),
771 source_scope: OUTERMOST_SOURCE_SCOPE,
772 guard_context: vec![],
773 fixed_temps: Default::default(),
774 fixed_temps_scope: None,
775 local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
776 canonical_user_type_annotations: IndexVec::new(),
777 upvars: CaptureMap::new(),
778 var_indices: Default::default(),
779 unit_temp: None,
780 var_debug_info: vec![],
781 lint_level_roots_cache: GrowableBitSet::new_empty(),
782 coverage_info: coverageinfo::CoverageInfoBuilder::new_if_enabled(tcx, def),
783 };
784
785 assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
786 assert_eq!(builder.new_source_scope(span, lint_level), OUTERMOST_SOURCE_SCOPE);
787 builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
788
789 builder
790 }
791
792 fn finish(self) -> Body<'tcx> {
793 let mut body = Body::new(
794 MirSource::item(self.def_id.to_def_id()),
795 self.cfg.basic_blocks,
796 self.source_scopes,
797 self.local_decls,
798 self.canonical_user_type_annotations,
799 self.arg_count,
800 self.var_debug_info,
801 self.fn_span,
802 self.coroutine,
803 None,
804 );
805 body.coverage_info_hi = self.coverage_info.map(|b| b.into_done());
806
807 for (index, block) in body.basic_blocks.iter().enumerate() {
808 if block.terminator.is_none() {
809 use rustc_middle::mir::pretty;
810 let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx);
811 pretty::write_mir_fn(
812 self.tcx,
813 &body,
814 &mut |_, _| Ok(()),
815 &mut std::io::stdout(),
816 options,
817 )
818 .unwrap();
819 span_bug!(self.fn_span, "no terminator on block {:?}", index);
820 }
821 }
822
823 body
824 }
825
826 fn insert_upvar_arg(&mut self) {
827 let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return };
828
829 let mut closure_ty = closure_arg.ty;
830 let mut closure_env_projs = vec![];
831 if let ty::Ref(_, ty, _) = closure_ty.kind() {
832 closure_env_projs.push(ProjectionElem::Deref);
833 closure_ty = *ty;
834 }
835
836 let upvar_args = match closure_ty.kind() {
837 ty::Closure(_, args) => ty::UpvarArgs::Closure(args),
838 ty::Coroutine(_, args) => ty::UpvarArgs::Coroutine(args),
839 ty::CoroutineClosure(_, args) => ty::UpvarArgs::CoroutineClosure(args),
840 _ => return,
841 };
842
843 let capture_tys = upvar_args.upvar_tys();
849
850 let tcx = self.tcx;
851 let mut upvar_owner = None;
852 self.upvars = tcx
853 .closure_captures(self.def_id)
854 .iter()
855 .zip_eq(capture_tys)
856 .enumerate()
857 .map(|(i, (captured_place, ty))| {
858 let name = captured_place.to_symbol();
859
860 let capture = captured_place.info.capture_kind;
861 let var_id = match captured_place.place.base {
862 HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
863 _ => bug!("Expected an upvar"),
864 };
865 let upvar_base = upvar_owner.get_or_insert(var_id.owner);
866 assert_eq!(*upvar_base, var_id.owner);
867 let var_id = var_id.local_id;
868
869 let mutability = captured_place.mutability;
870
871 let mut projs = closure_env_projs.clone();
872 projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
873 match capture {
874 ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {}
875 ty::UpvarCapture::ByRef(..) => {
876 projs.push(ProjectionElem::Deref);
877 }
878 };
879
880 let use_place = Place {
881 local: ty::CAPTURE_STRUCT_LOCAL,
882 projection: tcx.mk_place_elems(&projs),
883 };
884 self.var_debug_info.push(VarDebugInfo {
885 name,
886 source_info: SourceInfo::outermost(captured_place.var_ident.span),
887 value: VarDebugInfoContents::Place(use_place),
888 composite: None,
889 argument_index: None,
890 });
891
892 let capture = Capture { captured_place, use_place, mutability };
893 (var_id, capture)
894 })
895 .collect();
896 }
897
898 fn args_and_body(
899 &mut self,
900 mut block: BasicBlock,
901 arguments: &IndexSlice<ParamId, Param<'tcx>>,
902 argument_scope: region::Scope,
903 expr_id: ExprId,
904 ) -> BlockAnd<()> {
905 let expr_span = self.thir[expr_id].span;
906 for (argument_index, param) in arguments.iter().enumerate() {
908 let source_info =
909 SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span));
910 let arg_local =
911 self.local_decls.push(LocalDecl::with_source_info(param.ty, source_info));
912
913 if let Some(ref pat) = param.pat
915 && let Some(name) = pat.simple_ident()
916 {
917 self.var_debug_info.push(VarDebugInfo {
918 name,
919 source_info,
920 value: VarDebugInfoContents::Place(arg_local.into()),
921 composite: None,
922 argument_index: Some(argument_index as u16 + 1),
923 });
924 }
925 }
926
927 self.insert_upvar_arg();
928
929 let mut scope = None;
930 for (index, param) in arguments.iter().enumerate() {
932 let local = Local::new(index + 1);
934 let place = Place::from(local);
935
936 self.schedule_drop(
938 param.pat.as_ref().map_or(expr_span, |pat| pat.span),
939 argument_scope,
940 local,
941 DropKind::Value,
942 );
943
944 let Some(ref pat) = param.pat else {
945 continue;
946 };
947 let original_source_scope = self.source_scope;
948 let span = pat.span;
949 if let Some(arg_hir_id) = param.hir_id {
950 self.set_correct_source_scope_for_arg(arg_hir_id, original_source_scope, span);
951 }
952 match pat.kind {
953 PatKind::Binding {
955 var,
956 mode: BindingMode(ByRef::No, mutability),
957 subpattern: None,
958 ..
959 } => {
960 self.local_decls[local].mutability = mutability;
961 self.local_decls[local].source_info.scope = self.source_scope;
962 **self.local_decls[local].local_info.as_mut().unwrap_crate_local() =
963 if let Some(kind) = param.self_kind {
964 LocalInfo::User(BindingForm::ImplicitSelf(kind))
965 } else {
966 let binding_mode = BindingMode(ByRef::No, mutability);
967 LocalInfo::User(BindingForm::Var(VarBindingForm {
968 binding_mode,
969 opt_ty_info: param.ty_span,
970 opt_match_place: Some((None, span)),
971 pat_span: span,
972 }))
973 };
974 self.var_indices.insert(var, LocalsForNode::One(local));
975 }
976 _ => {
977 scope = self.declare_bindings(
978 scope,
979 expr_span,
980 &pat,
981 None,
982 Some((Some(&place), span)),
983 );
984 let place_builder = PlaceBuilder::from(local);
985 block = self.place_into_pattern(block, pat, place_builder, false).into_block();
986 }
987 }
988 self.source_scope = original_source_scope;
989 }
990
991 if let Some(source_scope) = scope {
993 self.source_scope = source_scope;
994 }
995
996 if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden)
997 || self.tcx.is_sdylib_interface_build()
998 {
999 let source_info = self.source_info(rustc_span::DUMMY_SP);
1000 self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
1001 self.cfg.start_new_block().unit()
1002 } else {
1003 match self.tcx.hir_node(self.hir_id) {
1005 hir::Node::Item(hir::Item {
1006 kind: hir::ItemKind::Fn { has_body: false, .. },
1007 ..
1008 }) => {
1009 self.tcx.dcx().span_delayed_bug(
1010 expr_span,
1011 format!("fn item without body has reached MIR building: {:?}", self.def_id),
1012 );
1013 }
1014 _ => {}
1015 }
1016 self.expr_into_dest(Place::return_place(), block, expr_id)
1017 }
1018 }
1019
1020 fn set_correct_source_scope_for_arg(
1021 &mut self,
1022 arg_hir_id: HirId,
1023 original_source_scope: SourceScope,
1024 pattern_span: Span,
1025 ) {
1026 let parent_id = self.source_scopes[original_source_scope]
1027 .local_data
1028 .as_ref()
1029 .unwrap_crate_local()
1030 .lint_root;
1031 self.maybe_new_source_scope(pattern_span, arg_hir_id, parent_id);
1032 }
1033
1034 fn get_unit_temp(&mut self) -> Place<'tcx> {
1035 match self.unit_temp {
1036 Some(tmp) => tmp,
1037 None => {
1038 let ty = self.tcx.types.unit;
1039 let fn_span = self.fn_span;
1040 let tmp = self.temp(ty, fn_span);
1041 self.unit_temp = Some(tmp);
1042 tmp
1043 }
1044 }
1045 }
1046}
1047
1048fn parse_float_into_constval<'tcx>(
1049 num: Symbol,
1050 float_ty: ty::FloatTy,
1051 neg: bool,
1052) -> Option<ConstValue<'tcx>> {
1053 parse_float_into_scalar(num, float_ty, neg).map(|s| ConstValue::Scalar(s.into()))
1054}
1055
1056pub(crate) fn parse_float_into_scalar(
1057 num: Symbol,
1058 float_ty: ty::FloatTy,
1059 neg: bool,
1060) -> Option<ScalarInt> {
1061 let num = num.as_str();
1062 match float_ty {
1063 ty::FloatTy::F16 => {
1065 let mut f = num.parse::<Half>().ok()?;
1066 if neg {
1067 f = -f;
1068 }
1069 Some(ScalarInt::from(f))
1070 }
1071 ty::FloatTy::F32 => {
1072 let Ok(rust_f) = num.parse::<f32>() else { return None };
1073 let mut f = num
1074 .parse::<Single>()
1075 .unwrap_or_else(|e| panic!("apfloat::ieee::Single failed to parse `{num}`: {e:?}"));
1076
1077 assert!(
1078 u128::from(rust_f.to_bits()) == f.to_bits(),
1079 "apfloat::ieee::Single gave different result for `{}`: \
1080 {}({:#x}) vs Rust's {}({:#x})",
1081 rust_f,
1082 f,
1083 f.to_bits(),
1084 Single::from_bits(rust_f.to_bits().into()),
1085 rust_f.to_bits()
1086 );
1087
1088 if neg {
1089 f = -f;
1090 }
1091
1092 Some(ScalarInt::from(f))
1093 }
1094 ty::FloatTy::F64 => {
1095 let Ok(rust_f) = num.parse::<f64>() else { return None };
1096 let mut f = num
1097 .parse::<Double>()
1098 .unwrap_or_else(|e| panic!("apfloat::ieee::Double failed to parse `{num}`: {e:?}"));
1099
1100 assert!(
1101 u128::from(rust_f.to_bits()) == f.to_bits(),
1102 "apfloat::ieee::Double gave different result for `{}`: \
1103 {}({:#x}) vs Rust's {}({:#x})",
1104 rust_f,
1105 f,
1106 f.to_bits(),
1107 Double::from_bits(rust_f.to_bits().into()),
1108 rust_f.to_bits()
1109 );
1110
1111 if neg {
1112 f = -f;
1113 }
1114
1115 Some(ScalarInt::from(f))
1116 }
1117 ty::FloatTy::F128 => {
1119 let mut f = num.parse::<Quad>().ok()?;
1120 if neg {
1121 f = -f;
1122 }
1123 Some(ScalarInt::from(f))
1124 }
1125 }
1126}
1127
1128mod block;
1134mod cfg;
1135mod coverageinfo;
1136mod custom;
1137mod expr;
1138mod matches;
1139mod misc;
1140mod scope;
1141
1142pub(crate) use expr::category::Category as ExprCategory;