rustc_mir_build/builder/custom/parse/
instruction.rs1use rustc_abi::{FieldIdx, VariantIdx};
2use rustc_middle::mir::interpret::Scalar;
3use rustc_middle::mir::*;
4use rustc_middle::thir::*;
5use rustc_middle::ty;
6use rustc_middle::ty::cast::mir_cast_kind;
7use rustc_span::Span;
8use rustc_span::source_map::Spanned;
9
10use super::{PResult, ParseCtxt, parse_by_kind};
11use crate::builder::custom::ParseError;
12use crate::builder::expr::as_constant::as_constant_inner;
13
14impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
15 pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
16 parse_by_kind!(self, expr_id, _, "statement",
17 @call(mir_storage_live, args) => {
18 Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
19 },
20 @call(mir_storage_dead, args) => {
21 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
22 },
23 @call(mir_assume, args) => {
24 let op = self.parse_operand(args[0])?;
25 Ok(StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(op))))
26 },
27 @call(mir_retag, args) => {
28 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
29 },
30 @call(mir_set_discriminant, args) => {
31 let place = self.parse_place(args[0])?;
32 let var = self.parse_integer_literal(args[1])? as u32;
33 Ok(StatementKind::SetDiscriminant {
34 place: Box::new(place),
35 variant_index: VariantIdx::from_u32(var),
36 })
37 },
38 ExprKind::Assign { lhs, rhs } => {
39 let lhs = self.parse_place(*lhs)?;
40 let rhs = self.parse_rvalue(*rhs)?;
41 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
42 },
43 )
44 }
45
46 pub(crate) fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
47 parse_by_kind!(self, expr_id, expr, "terminator",
48 @call(mir_return, _args) => {
49 Ok(TerminatorKind::Return)
50 },
51 @call(mir_goto, args) => {
52 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
53 },
54 @call(mir_unreachable, _args) => {
55 Ok(TerminatorKind::Unreachable)
56 },
57 @call(mir_unwind_resume, _args) => {
58 Ok(TerminatorKind::UnwindResume)
59 },
60 @call(mir_unwind_terminate, args) => {
61 Ok(TerminatorKind::UnwindTerminate(self.parse_unwind_terminate_reason(args[0])?))
62 },
63 @call(mir_drop, args) => {
64 Ok(TerminatorKind::Drop {
65 place: self.parse_place(args[0])?,
66 target: self.parse_return_to(args[1])?,
67 unwind: self.parse_unwind_action(args[2])?,
68 replace: false,
69 drop: None,
70 async_fut: None,
71 })
72 },
73 @call(mir_call, args) => {
74 self.parse_call(args)
75 },
76 @call(mir_tail_call, args) => {
77 self.parse_tail_call(args)
78 },
79 ExprKind::Match { scrutinee, arms, .. } => {
80 let discr = self.parse_operand(*scrutinee)?;
81 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
82 },
83 )
84 }
85
86 fn parse_unwind_terminate_reason(&self, expr_id: ExprId) -> PResult<UnwindTerminateReason> {
87 parse_by_kind!(self, expr_id, _, "unwind terminate reason",
88 @variant(mir_unwind_terminate_reason, Abi) => {
89 Ok(UnwindTerminateReason::Abi)
90 },
91 @variant(mir_unwind_terminate_reason, InCleanup) => {
92 Ok(UnwindTerminateReason::InCleanup)
93 },
94 )
95 }
96
97 fn parse_unwind_action(&self, expr_id: ExprId) -> PResult<UnwindAction> {
98 parse_by_kind!(self, expr_id, _, "unwind action",
99 @call(mir_unwind_continue, _args) => {
100 Ok(UnwindAction::Continue)
101 },
102 @call(mir_unwind_unreachable, _args) => {
103 Ok(UnwindAction::Unreachable)
104 },
105 @call(mir_unwind_terminate, args) => {
106 Ok(UnwindAction::Terminate(self.parse_unwind_terminate_reason(args[0])?))
107 },
108 @call(mir_unwind_cleanup, args) => {
109 Ok(UnwindAction::Cleanup(self.parse_block(args[0])?))
110 },
111 )
112 }
113
114 fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> {
115 parse_by_kind!(self, expr_id, _, "return block",
116 @call(mir_return_to, args) => {
117 self.parse_block(args[0])
118 },
119 )
120 }
121
122 fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
123 let Some((otherwise, rest)) = arms.split_last() else {
124 return Err(ParseError {
125 span,
126 item_description: "no arms".to_string(),
127 expected: "at least one arm".to_string(),
128 });
129 };
130
131 let otherwise = &self.thir[*otherwise];
132 let PatKind::Wild = otherwise.pattern.kind else {
133 return Err(ParseError {
134 span: otherwise.span,
135 item_description: format!("{:?}", otherwise.pattern.kind),
136 expected: "wildcard pattern".to_string(),
137 });
138 };
139 let otherwise = self.parse_block(otherwise.body)?;
140
141 let mut values = Vec::new();
142 let mut targets = Vec::new();
143 for arm in rest {
144 let arm = &self.thir[*arm];
145 let value = match arm.pattern.kind {
146 PatKind::Constant { value } => value,
147 PatKind::ExpandedConstant { ref subpattern, def_id: _ }
148 if let PatKind::Constant { value } = subpattern.kind =>
149 {
150 value
151 }
152 _ => {
153 return Err(ParseError {
154 span: arm.pattern.span,
155 item_description: format!("{:?}", arm.pattern.kind),
156 expected: "constant pattern".to_string(),
157 });
158 }
159 };
160 values.push(value.valtree.unwrap_leaf().to_bits_unchecked());
161 targets.push(self.parse_block(arm.body)?);
162 }
163
164 Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
165 }
166
167 fn parse_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
168 let (destination, call) = parse_by_kind!(self, args[0], _, "function call",
169 ExprKind::Assign { lhs, rhs } => (*lhs, *rhs),
170 );
171 let destination = self.parse_place(destination)?;
172 let target = self.parse_return_to(args[1])?;
173 let unwind = self.parse_unwind_action(args[2])?;
174
175 parse_by_kind!(self, call, _, "function call",
176 ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
177 let fun = self.parse_operand(*fun)?;
178 let args = args
179 .iter()
180 .map(|arg|
181 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
182 )
183 .collect::<PResult<Box<[_]>>>()?;
184 Ok(TerminatorKind::Call {
185 func: fun,
186 args,
187 destination,
188 target: Some(target),
189 unwind,
190 call_source: if *from_hir_call { CallSource::Normal } else {
191 CallSource::OverloadedOperator
192 },
193 fn_span: *fn_span,
194 })
195 },
196 )
197 }
198
199 fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
200 parse_by_kind!(self, args[0], _, "tail call",
201 ExprKind::Call { fun, args, fn_span, .. } => {
202 let fun = self.parse_operand(*fun)?;
203 let args = args
204 .iter()
205 .map(|arg|
206 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
207 )
208 .collect::<PResult<Box<[_]>>>()?;
209 Ok(TerminatorKind::TailCall {
210 func: fun,
211 args,
212 fn_span: *fn_span,
213 })
214 },
215 )
216 }
217
218 fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
219 parse_by_kind!(self, expr_id, expr, "rvalue",
220 @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
221 @call(mir_cast_transmute, args) => {
222 let source = self.parse_operand(args[0])?;
223 Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
224 },
225 @call(mir_cast_ptr_to_ptr, args) => {
226 let source = self.parse_operand(args[0])?;
227 Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty))
228 },
229 @call(mir_cast_unsize, args) => {
230 let source = self.parse_operand(args[0])?;
231 let kind = CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, CoercionSource::AsCast);
232 Ok(Rvalue::Cast(kind, source, expr.ty))
233 },
234 @call(mir_checked, args) => {
235 parse_by_kind!(self, args[0], _, "binary op",
236 ExprKind::Binary { op, lhs, rhs } => {
237 if let Some(op_with_overflow) = op.wrapping_to_overflowing() {
238 Ok(Rvalue::BinaryOp(
239 op_with_overflow, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
240 ))
241 } else {
242 Err(self.expr_error(expr_id, "No WithOverflow form of this operator"))
243 }
244 },
245 )
246 },
247 @call(mir_offset, args) => {
248 let ptr = self.parse_operand(args[0])?;
249 let offset = self.parse_operand(args[1])?;
250 Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
251 },
252 @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
253 ExprKind::Borrow { borrow_kind, arg } => Ok(
254 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
255 ),
256 ExprKind::RawBorrow { mutability, arg } => Ok(
257 Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?)
258 ),
259 ExprKind::Binary { op, lhs, rhs } => Ok(
260 Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
261 ),
262 ExprKind::Unary { op, arg } => Ok(
263 Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
264 ),
265 ExprKind::Repeat { value, count } => Ok(
266 Rvalue::Repeat(self.parse_operand(*value)?, *count)
267 ),
268 ExprKind::Cast { source } => {
269 let source = self.parse_operand(*source)?;
270 let source_ty = source.ty(self.body.local_decls(), self.tcx);
271 let cast_kind = mir_cast_kind(source_ty, expr.ty);
272 Ok(Rvalue::Cast(cast_kind, source, expr.ty))
273 },
274 ExprKind::Tuple { fields } => Ok(
275 Rvalue::Aggregate(
276 Box::new(AggregateKind::Tuple),
277 fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
278 )
279 ),
280 ExprKind::Array { fields } => {
281 let elem_ty = expr.ty.builtin_index().expect("ty must be an array");
282 Ok(Rvalue::Aggregate(
283 Box::new(AggregateKind::Array(elem_ty)),
284 fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
285 ))
286 },
287 ExprKind::Adt(box AdtExpr { adt_def, variant_index, args, fields, .. }) => {
288 let is_union = adt_def.is_union();
289 let active_field_index = is_union.then(|| fields[0].name);
290
291 Ok(Rvalue::Aggregate(
292 Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, args, None, active_field_index)),
293 fields.iter().map(|f| self.parse_operand(f.expr)).collect::<Result<_, _>>()?
294 ))
295 },
296 _ => self.parse_operand(expr_id).map(Rvalue::Use),
297 )
298 }
299
300 pub(crate) fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
301 parse_by_kind!(self, expr_id, expr, "operand",
302 @call(mir_move, args) => self.parse_place(args[0]).map(Operand::Move),
303 @call(mir_static, args) => self.parse_static(args[0]),
304 @call(mir_static_mut, args) => self.parse_static(args[0]),
305 ExprKind::Literal { .. }
306 | ExprKind::NamedConst { .. }
307 | ExprKind::NonHirLiteral { .. }
308 | ExprKind::ZstLiteral { .. }
309 | ExprKind::ConstParam { .. }
310 | ExprKind::ConstBlock { .. } => {
311 Ok(Operand::Constant(Box::new(
312 as_constant_inner(expr, |_| None, self.tcx)
313 )))
314 },
315 _ => self.parse_place(expr_id).map(Operand::Copy),
316 )
317 }
318
319 fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
320 self.parse_place_inner(expr_id).map(|(x, _)| x)
321 }
322
323 fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
324 let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
325 @call(mir_field, args) => {
326 let (parent, place_ty) = self.parse_place_inner(args[0])?;
327 let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
328 let field_ty = PlaceTy::field_ty(self.tcx, place_ty.ty, place_ty.variant_index, field);
329 let proj = PlaceElem::Field(field, field_ty);
330 let place = parent.project_deeper(&[proj], self.tcx);
331 return Ok((place, PlaceTy::from_ty(field_ty)));
332 },
333 @call(mir_variant, args) => {
334 (args[0], PlaceElem::Downcast(
335 None,
336 VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
337 ))
338 },
339 ExprKind::Deref { arg } => {
340 parse_by_kind!(self, *arg, _, "does not matter",
341 @call(mir_make_place, args) => return self.parse_place_inner(args[0]),
342 _ => (*arg, PlaceElem::Deref),
343 )
344 },
345 ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
346 ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
347 _ => {
348 let place = self.parse_local(expr_id).map(Place::from)?;
349 return Ok((place, PlaceTy::from_ty(expr.ty)))
350 },
351 );
352 let (parent, ty) = self.parse_place_inner(parent)?;
353 let place = parent.project_deeper(&[proj], self.tcx);
354 let ty = ty.projection_ty(self.tcx, proj);
355 Ok((place, ty))
356 }
357
358 fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
359 parse_by_kind!(self, expr_id, _, "local",
360 ExprKind::VarRef { id } => Ok(self.local_map[id]),
361 )
362 }
363
364 fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
365 parse_by_kind!(self, expr_id, _, "basic block",
366 ExprKind::VarRef { id } => Ok(self.block_map[id]),
367 )
368 }
369
370 fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
371 let expr_id = parse_by_kind!(self, expr_id, _, "static",
372 ExprKind::Deref { arg } => *arg,
373 );
374
375 parse_by_kind!(self, expr_id, expr, "static",
376 ExprKind::StaticRef { alloc_id, ty, .. } => {
377 let const_val =
378 ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
379 let const_ = Const::Val(const_val, *ty);
380
381 Ok(Operand::Constant(Box::new(ConstOperand {
382 span: expr.span,
383 user_ty: None,
384 const_
385 })))
386 },
387 )
388 }
389
390 fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
391 parse_by_kind!(self, expr_id, expr, "constant",
392 ExprKind::Literal { .. }
393 | ExprKind::NamedConst { .. }
394 | ExprKind::NonHirLiteral { .. }
395 | ExprKind::ConstBlock { .. } => Ok({
396 let value = as_constant_inner(expr, |_| None, self.tcx);
397 value.const_.eval_bits(self.tcx, self.typing_env)
398 }),
399 )
400 }
401}