]>
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 | }, | |
487cf647 FG |
21 | @call("mir_retag", args) => { |
22 | Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?))) | |
23 | }, | |
9c376795 FG |
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), | |
30 | }) | |
487cf647 FG |
31 | }, |
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)))) | |
36 | }, | |
37 | ) | |
38 | } | |
39 | ||
40 | pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> { | |
9c376795 | 41 | parse_by_kind!(self, expr_id, expr, "terminator", |
487cf647 FG |
42 | @call("mir_return", _args) => { |
43 | Ok(TerminatorKind::Return) | |
44 | }, | |
45 | @call("mir_goto", args) => { | |
46 | Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } ) | |
47 | }, | |
9c376795 FG |
48 | @call("mir_unreachable", _args) => { |
49 | Ok(TerminatorKind::Unreachable) | |
50 | }, | |
51 | @call("mir_drop", args) => { | |
52 | Ok(TerminatorKind::Drop { | |
53 | place: self.parse_place(args[0])?, | |
54 | target: self.parse_block(args[1])?, | |
55 | unwind: None, | |
56 | }) | |
57 | }, | |
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])?, | |
63 | unwind: None, | |
64 | }) | |
65 | }, | |
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) | |
70 | }, | |
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 }) | |
74 | }, | |
75 | ) | |
76 | } | |
77 | ||
78 | fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> { | |
79 | let Some((otherwise, rest)) = arms.split_last() else { | |
80 | return Err(ParseError { | |
81 | span, | |
82 | item_description: "no arms".to_string(), | |
83 | expected: "at least one arm".to_string(), | |
84 | }) | |
85 | }; | |
86 | ||
87 | let otherwise = &self.thir[*otherwise]; | |
88 | let PatKind::Wild = otherwise.pattern.kind else { | |
89 | return Err(ParseError { | |
90 | span: otherwise.span, | |
91 | item_description: format!("{:?}", otherwise.pattern.kind), | |
92 | expected: "wildcard pattern".to_string(), | |
93 | }) | |
94 | }; | |
95 | let otherwise = self.parse_block(otherwise.body)?; | |
96 | ||
97 | let mut values = Vec::new(); | |
98 | let mut targets = Vec::new(); | |
99 | for arm in rest { | |
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(), | |
106 | }) | |
107 | }; | |
108 | values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty)); | |
109 | targets.push(self.parse_block(arm.body)?); | |
110 | } | |
111 | ||
112 | Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise)) | |
113 | } | |
114 | ||
115 | fn parse_call( | |
116 | &self, | |
117 | expr_id: ExprId, | |
118 | destination: Place<'tcx>, | |
119 | target: BasicBlock, | |
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)?; | |
124 | let args = args | |
125 | .iter() | |
126 | .map(|arg| self.parse_operand(*arg)) | |
127 | .collect::<PResult<Vec<_>>>()?; | |
128 | Ok(TerminatorKind::Call { | |
129 | func: fun, | |
130 | args, | |
131 | destination, | |
132 | target: Some(target), | |
133 | cleanup: None, | |
134 | from_hir_call: *from_hir_call, | |
135 | fn_span: *fn_span, | |
136 | }) | |
137 | }, | |
487cf647 FG |
138 | ) |
139 | } | |
140 | ||
141 | fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> { | |
142 | parse_by_kind!(self, expr_id, _, "rvalue", | |
9c376795 | 143 | @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), |
487cf647 FG |
144 | ExprKind::Borrow { borrow_kind, arg } => Ok( |
145 | Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) | |
146 | ), | |
147 | ExprKind::AddressOf { mutability, arg } => Ok( | |
148 | Rvalue::AddressOf(*mutability, self.parse_place(*arg)?) | |
149 | ), | |
150 | _ => self.parse_operand(expr_id).map(Rvalue::Use), | |
151 | ) | |
152 | } | |
153 | ||
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( | |
9c376795 | 166 | as_constant_inner(expr, |_| None, self.tcx) |
487cf647 FG |
167 | ))) |
168 | }, | |
169 | _ => self.parse_place(expr_id).map(Operand::Copy), | |
170 | ) | |
171 | } | |
172 | ||
173 | fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> { | |
9c376795 FG |
174 | self.parse_place_inner(expr_id).map(|(x, _)| x) |
175 | } | |
176 | ||
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))); | |
186 | }, | |
187 | @call("mir_variant", args) => { | |
188 | (args[0], PlaceElem::Downcast( | |
189 | None, | |
190 | VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32) | |
191 | )) | |
192 | }, | |
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), | |
197 | ) | |
198 | }, | |
199 | ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)), | |
200 | ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)), | |
201 | _ => { | |
202 | let place = self.parse_local(expr_id).map(Place::from)?; | |
203 | return Ok((place, PlaceTy::from_ty(expr.ty))) | |
204 | }, | |
205 | ); | |
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); | |
209 | Ok((place, ty)) | |
487cf647 FG |
210 | } |
211 | ||
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]), | |
215 | ) | |
216 | } | |
217 | ||
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]), | |
221 | ) | |
222 | } | |
223 | ||
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, | |
227 | ); | |
228 | ||
229 | parse_by_kind!(self, expr_id, expr, "static", | |
230 | ExprKind::StaticRef { alloc_id, ty, .. } => { | |
231 | let const_val = | |
232 | ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx)); | |
233 | let literal = ConstantKind::Val(const_val, *ty); | |
234 | ||
235 | Ok(Operand::Constant(Box::new(Constant { | |
236 | span: expr.span, | |
237 | user_ty: None, | |
238 | literal | |
239 | }))) | |
240 | }, | |
241 | ) | |
242 | } | |
9c376795 FG |
243 | |
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()) | |
252 | }), | |
253 | ) | |
254 | } | |
487cf647 | 255 | } |