]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_mir_build / src / build / custom / parse / instruction.rs
CommitLineData
487cf647 1use rustc_middle::mir::interpret::{ConstValue, Scalar};
9c376795 2use rustc_middle::mir::tcx::PlaceTy;
487cf647 3use rustc_middle::{mir::*, thir::*, ty};
9c376795
FG
4use rustc_span::Span;
5use rustc_target::abi::VariantIdx;
6
7use crate::build::custom::ParseError;
8use crate::build::expr::as_constant::as_constant_inner;
487cf647
FG
9
10use super::{parse_by_kind, PResult, ParseCtxt};
11
12impl<'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",
9c376795
FG
15 @call("mir_storage_live", args) => {
16 Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
17 },
18 @call("mir_storage_dead", args) => {
19 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
20 },
9ffffee4
FG
21 @call("mir_deinit", args) => {
22 Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
23 },
487cf647
FG
24 @call("mir_retag", args) => {
25 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
26 },
9c376795
FG
27 @call("mir_set_discriminant", args) => {
28 let place = self.parse_place(args[0])?;
29 let var = self.parse_integer_literal(args[1])? as u32;
30 Ok(StatementKind::SetDiscriminant {
31 place: Box::new(place),
32 variant_index: VariantIdx::from_u32(var),
33 })
487cf647
FG
34 },
35 ExprKind::Assign { lhs, rhs } => {
36 let lhs = self.parse_place(*lhs)?;
37 let rhs = self.parse_rvalue(*rhs)?;
38 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
39 },
40 )
41 }
42
43 pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
9c376795 44 parse_by_kind!(self, expr_id, expr, "terminator",
487cf647
FG
45 @call("mir_return", _args) => {
46 Ok(TerminatorKind::Return)
47 },
48 @call("mir_goto", args) => {
49 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
50 },
9c376795
FG
51 @call("mir_unreachable", _args) => {
52 Ok(TerminatorKind::Unreachable)
53 },
54 @call("mir_drop", args) => {
55 Ok(TerminatorKind::Drop {
56 place: self.parse_place(args[0])?,
57 target: self.parse_block(args[1])?,
58 unwind: None,
59 })
60 },
61 @call("mir_drop_and_replace", args) => {
62 Ok(TerminatorKind::DropAndReplace {
63 place: self.parse_place(args[0])?,
64 value: self.parse_operand(args[1])?,
65 target: self.parse_block(args[2])?,
66 unwind: None,
67 })
68 },
69 @call("mir_call", args) => {
70 let destination = self.parse_place(args[0])?;
71 let target = self.parse_block(args[1])?;
72 self.parse_call(args[2], destination, target)
73 },
74 ExprKind::Match { scrutinee, arms } => {
75 let discr = self.parse_operand(*scrutinee)?;
76 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
77 },
78 )
79 }
80
81 fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
82 let Some((otherwise, rest)) = arms.split_last() else {
83 return Err(ParseError {
84 span,
85 item_description: "no arms".to_string(),
86 expected: "at least one arm".to_string(),
87 })
88 };
89
90 let otherwise = &self.thir[*otherwise];
91 let PatKind::Wild = otherwise.pattern.kind else {
92 return Err(ParseError {
93 span: otherwise.span,
94 item_description: format!("{:?}", otherwise.pattern.kind),
95 expected: "wildcard pattern".to_string(),
96 })
97 };
98 let otherwise = self.parse_block(otherwise.body)?;
99
100 let mut values = Vec::new();
101 let mut targets = Vec::new();
102 for arm in rest {
103 let arm = &self.thir[*arm];
104 let PatKind::Constant { value } = arm.pattern.kind else {
105 return Err(ParseError {
106 span: arm.pattern.span,
107 item_description: format!("{:?}", arm.pattern.kind),
108 expected: "constant pattern".to_string(),
109 })
110 };
111 values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
112 targets.push(self.parse_block(arm.body)?);
113 }
114
115 Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
116 }
117
118 fn parse_call(
119 &self,
120 expr_id: ExprId,
121 destination: Place<'tcx>,
122 target: BasicBlock,
123 ) -> PResult<TerminatorKind<'tcx>> {
124 parse_by_kind!(self, expr_id, _, "function call",
125 ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
126 let fun = self.parse_operand(*fun)?;
127 let args = args
128 .iter()
129 .map(|arg| self.parse_operand(*arg))
130 .collect::<PResult<Vec<_>>>()?;
131 Ok(TerminatorKind::Call {
132 func: fun,
133 args,
134 destination,
135 target: Some(target),
136 cleanup: None,
137 from_hir_call: *from_hir_call,
138 fn_span: *fn_span,
139 })
140 },
487cf647
FG
141 )
142 }
143
144 fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
145 parse_by_kind!(self, expr_id, _, "rvalue",
9c376795 146 @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
9ffffee4
FG
147 @call("mir_checked", args) => {
148 parse_by_kind!(self, args[0], _, "binary op",
149 ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
150 *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
151 )),
152 )
153 },
154 @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
487cf647
FG
155 ExprKind::Borrow { borrow_kind, arg } => Ok(
156 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
157 ),
158 ExprKind::AddressOf { mutability, arg } => Ok(
159 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
160 ),
9ffffee4
FG
161 ExprKind::Binary { op, lhs, rhs } => Ok(
162 Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
163 ),
164 ExprKind::Unary { op, arg } => Ok(
165 Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
166 ),
167 ExprKind::Repeat { value, count } => Ok(
168 Rvalue::Repeat(self.parse_operand(*value)?, *count)
169 ),
487cf647
FG
170 _ => self.parse_operand(expr_id).map(Rvalue::Use),
171 )
172 }
173
174 fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
175 parse_by_kind!(self, expr_id, expr, "operand",
176 @call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
177 @call("mir_static", args) => self.parse_static(args[0]),
178 @call("mir_static_mut", args) => self.parse_static(args[0]),
179 ExprKind::Literal { .. }
180 | ExprKind::NamedConst { .. }
181 | ExprKind::NonHirLiteral { .. }
182 | ExprKind::ZstLiteral { .. }
183 | ExprKind::ConstParam { .. }
184 | ExprKind::ConstBlock { .. } => {
185 Ok(Operand::Constant(Box::new(
9c376795 186 as_constant_inner(expr, |_| None, self.tcx)
487cf647
FG
187 )))
188 },
189 _ => self.parse_place(expr_id).map(Operand::Copy),
190 )
191 }
192
193 fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
9c376795
FG
194 self.parse_place_inner(expr_id).map(|(x, _)| x)
195 }
196
197 fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
198 let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
199 @call("mir_field", args) => {
200 let (parent, ty) = self.parse_place_inner(args[0])?;
201 let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
202 let field_ty = ty.field_ty(self.tcx, field);
203 let proj = PlaceElem::Field(field, field_ty);
204 let place = parent.project_deeper(&[proj], self.tcx);
205 return Ok((place, PlaceTy::from_ty(field_ty)));
206 },
207 @call("mir_variant", args) => {
208 (args[0], PlaceElem::Downcast(
209 None,
210 VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
211 ))
212 },
213 ExprKind::Deref { arg } => {
214 parse_by_kind!(self, *arg, _, "does not matter",
215 @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
216 _ => (*arg, PlaceElem::Deref),
217 )
218 },
219 ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
220 ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
221 _ => {
222 let place = self.parse_local(expr_id).map(Place::from)?;
223 return Ok((place, PlaceTy::from_ty(expr.ty)))
224 },
225 );
226 let (parent, ty) = self.parse_place_inner(parent)?;
227 let place = parent.project_deeper(&[proj], self.tcx);
228 let ty = ty.projection_ty(self.tcx, proj);
229 Ok((place, ty))
487cf647
FG
230 }
231
232 fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
233 parse_by_kind!(self, expr_id, _, "local",
234 ExprKind::VarRef { id } => Ok(self.local_map[id]),
235 )
236 }
237
238 fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
239 parse_by_kind!(self, expr_id, _, "basic block",
240 ExprKind::VarRef { id } => Ok(self.block_map[id]),
241 )
242 }
243
244 fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
245 let expr_id = parse_by_kind!(self, expr_id, _, "static",
246 ExprKind::Deref { arg } => *arg,
247 );
248
249 parse_by_kind!(self, expr_id, expr, "static",
250 ExprKind::StaticRef { alloc_id, ty, .. } => {
251 let const_val =
252 ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
253 let literal = ConstantKind::Val(const_val, *ty);
254
255 Ok(Operand::Constant(Box::new(Constant {
256 span: expr.span,
257 user_ty: None,
258 literal
259 })))
260 },
261 )
262 }
9c376795
FG
263
264 fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
265 parse_by_kind!(self, expr_id, expr, "constant",
266 ExprKind::Literal { .. }
267 | ExprKind::NamedConst { .. }
268 | ExprKind::NonHirLiteral { .. }
269 | ExprKind::ConstBlock { .. } => Ok({
270 let value = as_constant_inner(expr, |_| None, self.tcx);
271 value.literal.eval_bits(self.tcx, self.param_env, value.ty())
272 }),
273 )
274 }
487cf647 275}