]>
Commit | Line | Data |
---|---|---|
487cf647 | 1 | use rustc_middle::mir::interpret::{ConstValue, Scalar}; |
9c376795 | 2 | use rustc_middle::mir::tcx::PlaceTy; |
487cf647 | 3 | use rustc_middle::{mir::*, thir::*, ty}; |
9c376795 FG |
4 | use rustc_span::Span; |
5 | use rustc_target::abi::VariantIdx; | |
6 | ||
7 | use crate::build::custom::ParseError; | |
8 | use crate::build::expr::as_constant::as_constant_inner; | |
487cf647 FG |
9 | |
10 | use super::{parse_by_kind, PResult, ParseCtxt}; | |
11 | ||
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", | |
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 | } |