rustc_mir_build/builder/custom/
mod.rs1use rustc_data_structures::fx::FxHashMap;
21use rustc_hir::def_id::DefId;
22use rustc_hir::{HirId, attrs};
23use rustc_index::{IndexSlice, IndexVec};
24use rustc_middle::bug;
25use rustc_middle::mir::*;
26use rustc_middle::thir::*;
27use rustc_middle::ty::{self, Ty, TyCtxt};
28use rustc_span::Span;
29
30mod parse;
31
32pub(super) fn build_custom_mir<'tcx>(
33 tcx: TyCtxt<'tcx>,
34 did: DefId,
35 hir_id: HirId,
36 thir: &Thir<'tcx>,
37 expr: ExprId,
38 params: &IndexSlice<ParamId, Param<'tcx>>,
39 return_ty: Ty<'tcx>,
40 return_ty_span: Span,
41 span: Span,
42 dialect: Option<attrs::MirDialect>,
43 phase: Option<attrs::MirPhase>,
44) -> Body<'tcx> {
45 let mut body = Body {
46 basic_blocks: BasicBlocks::new(IndexVec::new()),
47 source: MirSource::item(did),
48 phase: MirPhase::Built,
49 source_scopes: IndexVec::new(),
50 coroutine: None,
51 local_decls: IndexVec::new(),
52 user_type_annotations: IndexVec::new(),
53 arg_count: params.len(),
54 spread_arg: None,
55 var_debug_info: Vec::new(),
56 span,
57 required_consts: None,
58 mentioned_items: None,
59 is_polymorphic: false,
60 tainted_by_errors: None,
61 injection_phase: None,
62 pass_count: 0,
63 coverage_info_hi: None,
64 function_coverage_info: None,
65 };
66
67 body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
68 body.basic_blocks_mut().push(BasicBlockData::new(None, false));
69 body.source_scopes.push(SourceScopeData {
70 span,
71 parent_scope: None,
72 inlined: None,
73 inlined_parent_scope: None,
74 local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
75 });
76 body.injection_phase = Some(parse_attribute(dialect, phase));
77
78 let mut pctxt = ParseCtxt {
79 tcx,
80 typing_env: body.typing_env(tcx),
81 thir,
82 source_scope: OUTERMOST_SOURCE_SCOPE,
83 body: &mut body,
84 local_map: FxHashMap::default(),
85 block_map: FxHashMap::default(),
86 };
87
88 let res: PResult<_> = try {
89 pctxt.parse_args(params)?;
90 pctxt.parse_body(expr)?;
91 };
92 if let Err(err) = res {
93 tcx.dcx().span_fatal(
94 err.span,
95 format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
96 )
97 }
98
99 body
100}
101
102fn parse_attribute(dialect: Option<attrs::MirDialect>, phase: Option<attrs::MirPhase>) -> MirPhase {
105 let Some(dialect) = dialect else {
106 assert!(phase.is_none());
108 return MirPhase::Built;
109 };
110
111 match dialect {
112 attrs::MirDialect::Built => {
113 assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
115 MirPhase::Built
116 }
117 attrs::MirDialect::Analysis => match phase {
118 None | Some(attrs::MirPhase::Initial) => MirPhase::Analysis(AnalysisPhase::Initial),
119
120 Some(attrs::MirPhase::PostCleanup) => MirPhase::Analysis(AnalysisPhase::PostCleanup),
121
122 Some(attrs::MirPhase::Optimized) => {
123 bug!("`optimized` dialect is not compatible with the `analysis` dialect")
125 }
126 },
127
128 attrs::MirDialect::Runtime => match phase {
129 None | Some(attrs::MirPhase::Initial) => MirPhase::Runtime(RuntimePhase::Initial),
130 Some(attrs::MirPhase::PostCleanup) => MirPhase::Runtime(RuntimePhase::PostCleanup),
131 Some(attrs::MirPhase::Optimized) => MirPhase::Runtime(RuntimePhase::Optimized),
132 },
133 }
134}
135
136struct ParseCtxt<'a, 'tcx> {
137 tcx: TyCtxt<'tcx>,
138 typing_env: ty::TypingEnv<'tcx>,
139 thir: &'a Thir<'tcx>,
140 source_scope: SourceScope,
141 body: &'a mut Body<'tcx>,
142 local_map: FxHashMap<LocalVarId, Local>,
143 block_map: FxHashMap<LocalVarId, BasicBlock>,
144}
145
146struct ParseError {
147 span: Span,
148 item_description: String,
149 expected: String,
150}
151
152impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
153 fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError {
154 let expr = &self.thir[expr];
155 ParseError {
156 span: expr.span,
157 item_description: format!("{:?}", expr.kind),
158 expected: expected.to_string(),
159 }
160 }
161
162 fn stmt_error(&self, stmt: StmtId, expected: &'static str) -> ParseError {
163 let stmt = &self.thir[stmt];
164 let span = match stmt.kind {
165 StmtKind::Expr { expr, .. } => self.thir[expr].span,
166 StmtKind::Let { span, .. } => span,
167 };
168 ParseError {
169 span,
170 item_description: format!("{:?}", stmt.kind),
171 expected: expected.to_string(),
172 }
173 }
174}
175
176type PResult<T> = Result<T, ParseError>;