1 use rustc_middle::mir::interpret::{ConstValue, Scalar};
2 use rustc_middle::mir::tcx::PlaceTy;
3 use rustc_middle::{mir::*, thir::*, ty};
5 use rustc_target::abi::VariantIdx;
7 use crate::build::custom::ParseError;
8 use crate::build::expr::as_constant::as_constant_inner;
10 use super::{parse_by_kind, PResult, ParseCtxt};
12 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
13 pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
14 parse_by_kind!(self, expr_id, _, "statement",
15 @call("mir_storage_live", args) => {
16 Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
18 @call("mir_storage_dead", args) => {
19 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
21 @call("mir_retag", args) => {
22 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
24 @call("mir_set_discriminant", args) => {
25 let place = self.parse_place(args[0])?;
26 let var = self.parse_integer_literal(args[1])? as u32;
27 Ok(StatementKind::SetDiscriminant {
28 place: Box::new(place),
29 variant_index: VariantIdx::from_u32(var),
32 ExprKind::Assign { lhs, rhs } => {
33 let lhs = self.parse_place(*lhs)?;
34 let rhs = self.parse_rvalue(*rhs)?;
35 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
40 pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
41 parse_by_kind!(self, expr_id, expr, "terminator",
42 @call("mir_return", _args) => {
43 Ok(TerminatorKind::Return)
45 @call("mir_goto", args) => {
46 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
48 @call("mir_unreachable", _args) => {
49 Ok(TerminatorKind::Unreachable)
51 @call("mir_drop", args) => {
52 Ok(TerminatorKind::Drop {
53 place: self.parse_place(args[0])?,
54 target: self.parse_block(args[1])?,
58 @call("mir_drop_and_replace", args) => {
59 Ok(TerminatorKind::DropAndReplace {
60 place: self.parse_place(args[0])?,
61 value: self.parse_operand(args[1])?,
62 target: self.parse_block(args[2])?,
66 @call("mir_call", args) => {
67 let destination = self.parse_place(args[0])?;
68 let target = self.parse_block(args[1])?;
69 self.parse_call(args[2], destination, target)
71 ExprKind::Match { scrutinee, arms } => {
72 let discr = self.parse_operand(*scrutinee)?;
73 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
78 fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
79 let Some((otherwise, rest)) = arms.split_last() else {
80 return Err(ParseError {
82 item_description: "no arms".to_string(),
83 expected: "at least one arm".to_string(),
87 let otherwise = &self.thir[*otherwise];
88 let PatKind::Wild = otherwise.pattern.kind else {
89 return Err(ParseError {
91 item_description: format!("{:?}", otherwise.pattern.kind),
92 expected: "wildcard pattern".to_string(),
95 let otherwise = self.parse_block(otherwise.body)?;
97 let mut values = Vec::new();
98 let mut targets = Vec::new();
100 let arm = &self.thir[*arm];
101 let PatKind::Constant { value } = arm.pattern.kind else {
102 return Err(ParseError {
103 span: arm.pattern.span,
104 item_description: format!("{:?}", arm.pattern.kind),
105 expected: "constant pattern".to_string(),
108 values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
109 targets.push(self.parse_block(arm.body)?);
112 Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
118 destination: Place<'tcx>,
120 ) -> PResult<TerminatorKind<'tcx>> {
121 parse_by_kind!(self, expr_id, _, "function call",
122 ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
123 let fun = self.parse_operand(*fun)?;
126 .map(|arg| self.parse_operand(*arg))
127 .collect::<PResult<Vec<_>>>()?;
128 Ok(TerminatorKind::Call {
132 target: Some(target),
134 from_hir_call: *from_hir_call,
141 fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
142 parse_by_kind!(self, expr_id, _, "rvalue",
143 @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
144 ExprKind::Borrow { borrow_kind, arg } => Ok(
145 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
147 ExprKind::AddressOf { mutability, arg } => Ok(
148 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
150 _ => self.parse_operand(expr_id).map(Rvalue::Use),
154 fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
155 parse_by_kind!(self, expr_id, expr, "operand",
156 @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
157 @call("mir_static", args) => self.parse_static(args[0]),
158 @call("mir_static_mut", args) => self.parse_static(args[0]),
159 ExprKind::Literal { .. }
160 | ExprKind::NamedConst { .. }
161 | ExprKind::NonHirLiteral { .. }
162 | ExprKind::ZstLiteral { .. }
163 | ExprKind::ConstParam { .. }
164 | ExprKind::ConstBlock { .. } => {
165 Ok(Operand::Constant(Box::new(
166 as_constant_inner(expr, |_| None, self.tcx)
169 _ => self.parse_place(expr_id).map(Operand::Copy),
173 fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
174 self.parse_place_inner(expr_id).map(|(x, _)| x)
177 fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
178 let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
179 @call("mir_field", args) => {
180 let (parent, ty) = self.parse_place_inner(args[0])?;
181 let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
182 let field_ty = ty.field_ty(self.tcx, field);
183 let proj = PlaceElem::Field(field, field_ty);
184 let place = parent.project_deeper(&[proj], self.tcx);
185 return Ok((place, PlaceTy::from_ty(field_ty)));
187 @call("mir_variant", args) => {
188 (args[0], PlaceElem::Downcast(
190 VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
193 ExprKind::Deref { arg } => {
194 parse_by_kind!(self, *arg, _, "does not matter",
195 @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
196 _ => (*arg, PlaceElem::Deref),
199 ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
200 ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
202 let place = self.parse_local(expr_id).map(Place::from)?;
203 return Ok((place, PlaceTy::from_ty(expr.ty)))
206 let (parent, ty) = self.parse_place_inner(parent)?;
207 let place = parent.project_deeper(&[proj], self.tcx);
208 let ty = ty.projection_ty(self.tcx, proj);
212 fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
213 parse_by_kind!(self, expr_id, _, "local",
214 ExprKind::VarRef { id } => Ok(self.local_map[id]),
218 fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
219 parse_by_kind!(self, expr_id, _, "basic block",
220 ExprKind::VarRef { id } => Ok(self.block_map[id]),
224 fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
225 let expr_id = parse_by_kind!(self, expr_id, _, "static",
226 ExprKind::Deref { arg } => *arg,
229 parse_by_kind!(self, expr_id, expr, "static",
230 ExprKind::StaticRef { alloc_id, ty, .. } => {
232 ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
233 let literal = ConstantKind::Val(const_val, *ty);
235 Ok(Operand::Constant(Box::new(Constant {
244 fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
245 parse_by_kind!(self, expr_id, expr, "constant",
246 ExprKind::Literal { .. }
247 | ExprKind::NamedConst { .. }
248 | ExprKind::NonHirLiteral { .. }
249 | ExprKind::ConstBlock { .. } => Ok({
250 let value = as_constant_inner(expr, |_| None, self.tcx);
251 value.literal.eval_bits(self.tcx, self.param_env, value.ty())