rustc_mir_build/builder/custom/parse/
instruction.rs

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