charon_driver/translate/
get_mir.rs1use std::panic;
4
5use crate::hax;
6use crate::hax::UnderOwnerState;
7use rustc_middle::mir;
8use rustc_middle::ty;
9
10use charon_lib::ast::*;
11use charon_lib::options::MirLevel;
12
13use super::translate_ctx::ItemTransCtx;
14
15impl<'tcx> ItemTransCtx<'tcx, '_> {
16 pub fn get_mir(
17 &mut self,
18 item_ref: &hax::ItemRef<'tcx>,
19 span: Span,
20 ) -> Result<Option<mir::Body<'tcx>>, Error> {
21 let _guard = charon_lib::timing::scope("get-mir");
22 let mut this = panic::AssertUnwindSafe(&mut *self);
24 let res = panic::catch_unwind(move || this.get_mir_inner(item_ref));
25 match res {
26 Ok(Ok(body)) => Ok(body),
27 Ok(Err(e)) => Err(e),
29 Err(_) => {
30 raise_error!(self, span, "Thread panicked when extracting body.");
31 }
32 }
33 }
34
35 fn get_mir_inner(
36 &mut self,
37 item_ref: &hax::ItemRef<'tcx>,
38 ) -> Result<Option<mir::Body<'tcx>>, Error> {
39 let tcx = self.t_ctx.tcx;
40 let mir_level = self.t_ctx.options.mir_level;
41 let def_id = &item_ref.def_id;
42 Ok(match get_mir_for_def_id_and_level(tcx, def_id, mir_level) {
43 Some(body) => {
44 let s = self.hax_state_with_id();
45 Some(if self.monomorphize() {
46 let typing_env = s.typing_env();
47 let args = item_ref.rustc_args(s);
48 hax::substitute(tcx, typing_env, Some(args), body)
49 } else {
50 body
51 })
52 }
53 None => None,
54 })
55 }
56}
57
58#[tracing::instrument(skip(tcx))]
61fn get_mir_for_def_id_and_level<'tcx>(
62 tcx: ty::TyCtxt<'tcx>,
63 def_id: &hax::DefId,
64 level: MirLevel,
65) -> Option<mir::Body<'tcx>> {
66 match def_id.base {
67 hax::DefIdBase::Real(rust_def_id) => {
68 if let Some(local_def_id) = rust_def_id.as_local() {
69 match level {
70 MirLevel::Built => {
71 let body = tcx.mir_built(local_def_id);
72 if !body.is_stolen() {
73 return Some(body.borrow().clone());
74 }
75 }
76 MirLevel::Promoted => {
77 let (body, _) = tcx.mir_promoted(local_def_id);
78 if !body.is_stolen() {
79 return Some(body.borrow().clone());
80 }
81 }
82 MirLevel::Elaborated => {
83 let body = tcx.mir_drops_elaborated_and_const_checked(local_def_id);
84 if !body.is_stolen() {
85 return Some(body.borrow().clone());
86 }
87 }
88 MirLevel::Optimized => {}
89 }
90 }
92
93 let is_global = matches!(
100 def_id.kind,
101 hax::DefKind::Const | hax::DefKind::AnonConst | hax::DefKind::AssocConst
102 );
103 let is_static = matches!(def_id.kind, hax::DefKind::Static { .. });
104 let mir_available = tcx.is_mir_available(rust_def_id);
105
106 if mir_available && !is_global && !is_static {
107 Some(tcx.optimized_mir(rust_def_id).clone())
108 } else if (is_global && !tcx.is_trivial_const(rust_def_id))
109 || (is_static && rust_def_id.is_local())
110 || tcx.is_const_fn(rust_def_id)
111 {
112 Some(tcx.mir_for_ctfe(rust_def_id).clone())
113 } else {
114 trace!("mir not available for {:?}", rust_def_id);
115 None
116 }
117 }
118 hax::DefIdBase::Promoted(rust_def_id, promoted_id) => {
119 let body =
120 rustc_const_uneval::promoted_body(tcx, rust_def_id, promoted_id, Clone::clone);
121 Some(body)
122 }
123 hax::DefIdBase::Alloc(..) => None,
124 _ => unreachable!(),
125 }
126}