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