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