]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
Rollup merge of #106946 - dtolnay:hashlinecolumn, r=m-ou-se
[rust.git] / compiler / rustc_mir_build / src / build / custom / parse / instruction.rs
1 use rustc_middle::mir::interpret::{ConstValue, Scalar};
2 use rustc_middle::mir::tcx::PlaceTy;
3 use rustc_middle::{mir::*, thir::*, ty};
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;
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",
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             },
21             @call("mir_retag", args) => {
22                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
23             },
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                 })
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>> {
41         parse_by_kind!(self, expr_id, expr, "terminator",
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             },
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             },
138         )
139     }
140
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)?)
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(
166                     as_constant_inner(expr, |_| None, self.tcx)
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>> {
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))
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     }
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     }
255 }