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