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}