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 drop: None,
73 async_fut: None,
74 })
75 },
76 @call(mir_call, args) => {
77 self.parse_call(args)
78 },
79 @call(mir_tail_call, args) => {
80 self.parse_tail_call(args)
81 },
82 ExprKind::Match { scrutinee, arms, .. } => {
83 let discr = self.parse_operand(*scrutinee)?;
84 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
85 },
86 )
87 }
88
89 fn parse_unwind_terminate_reason(&self, expr_id: ExprId) -> PResult<UnwindTerminateReason> {
90 parse_by_kind!(self, expr_id, _, "unwind terminate reason",
91 @variant(mir_unwind_terminate_reason, Abi) => {
92 Ok(UnwindTerminateReason::Abi)
93 },
94 @variant(mir_unwind_terminate_reason, InCleanup) => {
95 Ok(UnwindTerminateReason::InCleanup)
96 },
97 )
98 }
99
100 fn parse_unwind_action(&self, expr_id: ExprId) -> PResult<UnwindAction> {
101 parse_by_kind!(self, expr_id, _, "unwind action",
102 @call(mir_unwind_continue, _args) => {
103 Ok(UnwindAction::Continue)
104 },
105 @call(mir_unwind_unreachable, _args) => {
106 Ok(UnwindAction::Unreachable)
107 },
108 @call(mir_unwind_terminate, args) => {
109 Ok(UnwindAction::Terminate(self.parse_unwind_terminate_reason(args[0])?))
110 },
111 @call(mir_unwind_cleanup, args) => {
112 Ok(UnwindAction::Cleanup(self.parse_block(args[0])?))
113 },
114 )
115 }
116
117 fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> {
118 parse_by_kind!(self, expr_id, _, "return block",
119 @call(mir_return_to, args) => {
120 self.parse_block(args[0])
121 },
122 )
123 }
124
125 fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
126 let Some((otherwise, rest)) = arms.split_last() else {
127 return Err(ParseError {
128 span,
129 item_description: "no arms".to_string(),
130 expected: "at least one arm".to_string(),
131 });
132 };
133
134 let otherwise = &self.thir[*otherwise];
135 let PatKind::Wild = otherwise.pattern.kind else {
136 return Err(ParseError {
137 span: otherwise.span,
138 item_description: format!("{:?}", otherwise.pattern.kind),
139 expected: "wildcard pattern".to_string(),
140 });
141 };
142 let otherwise = self.parse_block(otherwise.body)?;
143
144 let mut values = Vec::new();
145 let mut targets = Vec::new();
146 for arm in rest {
147 let arm = &self.thir[*arm];
148 let value = match arm.pattern.kind {
149 PatKind::Constant { value } => value,
150 PatKind::ExpandedConstant { ref subpattern, def_id: _ }
151 if let PatKind::Constant { value } = subpattern.kind =>
152 {
153 value
154 }
155 _ => {
156 return Err(ParseError {
157 span: arm.pattern.span,
158 item_description: format!("{:?}", arm.pattern.kind),
159 expected: "constant pattern".to_string(),
160 });
161 }
162 };
163 values.push(value.eval_bits(self.tcx, self.typing_env));
164 targets.push(self.parse_block(arm.body)?);
165 }
166
167 Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
168 }
169
170 fn parse_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
171 let (destination, call) = parse_by_kind!(self, args[0], _, "function call",
172 ExprKind::Assign { lhs, rhs } => (*lhs, *rhs),
173 );
174 let destination = self.parse_place(destination)?;
175 let target = self.parse_return_to(args[1])?;
176 let unwind = self.parse_unwind_action(args[2])?;
177
178 parse_by_kind!(self, call, _, "function call",
179 ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
180 let fun = self.parse_operand(*fun)?;
181 let args = args
182 .iter()
183 .map(|arg|
184 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
185 )
186 .collect::<PResult<Box<[_]>>>()?;
187 Ok(TerminatorKind::Call {
188 func: fun,
189 args,
190 destination,
191 target: Some(target),
192 unwind,
193 call_source: if *from_hir_call { CallSource::Normal } else {
194 CallSource::OverloadedOperator
195 },
196 fn_span: *fn_span,
197 })
198 },
199 )
200 }
201
202 fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
203 parse_by_kind!(self, args[0], _, "tail call",
204 ExprKind::Call { fun, args, fn_span, .. } => {
205 let fun = self.parse_operand(*fun)?;
206 let args = args
207 .iter()
208 .map(|arg|
209 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
210 )
211 .collect::<PResult<Box<[_]>>>()?;
212 Ok(TerminatorKind::TailCall {
213 func: fun,
214 args,
215 fn_span: *fn_span,
216 })
217 },
218 )
219 }
220
221 fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
222 parse_by_kind!(self, expr_id, expr, "rvalue",
223 @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
224 @call(mir_cast_transmute, args) => {
225 let source = self.parse_operand(args[0])?;
226 Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
227 },
228 @call(mir_cast_ptr_to_ptr, args) => {
229 let source = self.parse_operand(args[0])?;
230 Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty))
231 },
232 @call(mir_checked, args) => {
233 parse_by_kind!(self, args[0], _, "binary op",
234 ExprKind::Binary { op, lhs, rhs } => {
235 if let Some(op_with_overflow) = op.wrapping_to_overflowing() {
236 Ok(Rvalue::BinaryOp(
237 op_with_overflow, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
238 ))
239 } else {
240 Err(self.expr_error(expr_id, "No WithOverflow form of this operator"))
241 }
242 },
243 )
244 },
245 @call(mir_offset, args) => {
246 let ptr = self.parse_operand(args[0])?;
247 let offset = self.parse_operand(args[1])?;
248 Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
249 },
250 @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
251 @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
252 @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(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, 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 = ty.field_ty(self.tcx, 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}