rustc_mir_build/builder/custom/parse/
instruction.rs

1use 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}