rustc_mir_build/builder/custom/
mod.rs1use rustc_data_structures::fx::FxHashMap;
21use rustc_hir::def_id::DefId;
22use rustc_hir::{Attribute, HirId};
23use rustc_index::{IndexSlice, IndexVec};
24use rustc_middle::mir::*;
25use rustc_middle::span_bug;
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 attr: &Attribute,
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_info_hi: None,
63 function_coverage_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(attr));
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: PResult<_> = 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 format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
95 )
96 }
97
98 body
99}
100
101fn parse_attribute(attr: &Attribute) -> MirPhase {
102 let meta_items = attr.meta_item_list().unwrap();
103 let mut dialect: Option<String> = None;
104 let mut phase: Option<String> = None;
105
106 for nested in meta_items {
108 let name = nested.name().unwrap();
109 let value = nested.value_str().unwrap().as_str().to_string();
110 match name.as_str() {
111 "dialect" => {
112 assert!(dialect.is_none());
113 dialect = Some(value);
114 }
115 "phase" => {
116 assert!(phase.is_none());
117 phase = Some(value);
118 }
119 other => {
120 span_bug!(
121 nested.span(),
122 "Unexpected key while parsing custom_mir attribute: '{}'",
123 other
124 );
125 }
126 }
127 }
128
129 let Some(dialect) = dialect else {
130 assert!(phase.is_none());
131 return MirPhase::Built;
132 };
133
134 MirPhase::parse(dialect, phase)
135}
136
137struct ParseCtxt<'a, 'tcx> {
138 tcx: TyCtxt<'tcx>,
139 typing_env: ty::TypingEnv<'tcx>,
140 thir: &'a Thir<'tcx>,
141 source_scope: SourceScope,
142 body: &'a mut Body<'tcx>,
143 local_map: FxHashMap<LocalVarId, Local>,
144 block_map: FxHashMap<LocalVarId, BasicBlock>,
145}
146
147struct ParseError {
148 span: Span,
149 item_description: String,
150 expected: String,
151}
152
153impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
154 fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError {
155 let expr = &self.thir[expr];
156 ParseError {
157 span: expr.span,
158 item_description: format!("{:?}", expr.kind),
159 expected: expected.to_string(),
160 }
161 }
162
163 fn stmt_error(&self, stmt: StmtId, expected: &'static str) -> ParseError {
164 let stmt = &self.thir[stmt];
165 let span = match stmt.kind {
166 StmtKind::Expr { expr, .. } => self.thir[expr].span,
167 StmtKind::Let { span, .. } => span,
168 };
169 ParseError {
170 span,
171 item_description: format!("{:?}", stmt.kind),
172 expected: expected.to_string(),
173 }
174 }
175}
176
177type PResult<T> = Result<T, ParseError>;