]>
Commit | Line | Data |
---|---|---|
923072b8 | 1 | pub(crate) use crate::build::expr::as_constant::lit_to_mir_constant; |
6a06907d | 2 | use crate::build::expr::as_place::PlaceBuilder; |
dc9dc135 | 3 | use crate::build::scope::DropKind; |
923072b8 FG |
4 | use rustc_apfloat::ieee::{Double, Single}; |
5 | use rustc_apfloat::Float; | |
353b0b11 | 6 | use rustc_ast::attr; |
923072b8 | 7 | use rustc_data_structures::fx::FxHashMap; |
f2b60f7d | 8 | use rustc_data_structures::sorted_map::SortedIndexMultiMap; |
5e7ed085 | 9 | use rustc_errors::ErrorGuaranteed; |
dfeec247 | 10 | use rustc_hir as hir; |
f2b60f7d | 11 | use rustc_hir::def::DefKind; |
f9f354fc | 12 | use rustc_hir::def_id::{DefId, LocalDefId}; |
923072b8 | 13 | use rustc_hir::{GeneratorKind, Node}; |
49aad941 | 14 | use rustc_index::{Idx, IndexSlice, IndexVec}; |
6a06907d | 15 | use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; |
fc512014 | 16 | use rustc_middle::hir::place::PlaceBase as HirPlaceBase; |
ba9703b0 | 17 | use rustc_middle::middle::region; |
923072b8 FG |
18 | use rustc_middle::mir::interpret::ConstValue; |
19 | use rustc_middle::mir::interpret::Scalar; | |
ba9703b0 | 20 | use rustc_middle::mir::*; |
f2b60f7d FG |
21 | use rustc_middle::thir::{ |
22 | self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, | |
23 | }; | |
9ffffee4 | 24 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; |
94222f64 | 25 | use rustc_span::symbol::sym; |
dfeec247 | 26 | use rustc_span::Span; |
923072b8 | 27 | use rustc_span::Symbol; |
353b0b11 | 28 | use rustc_target::abi::FieldIdx; |
dfeec247 | 29 | use rustc_target::spec::abi::Abi; |
3157f602 | 30 | |
0bf4aa26 XL |
31 | use super::lints; |
32 | ||
9c376795 FG |
33 | pub(crate) fn mir_built( |
34 | tcx: TyCtxt<'_>, | |
49aad941 | 35 | def: LocalDefId, |
9c376795 | 36 | ) -> &rustc_data_structures::steal::Steal<Body<'_>> { |
49aad941 | 37 | tcx.alloc_steal_mir(mir_build(tcx, def)) |
dfeec247 XL |
38 | } |
39 | ||
9fa01778 | 40 | /// Construct the MIR for a given `DefId`. |
49aad941 | 41 | fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { |
c295e0f8 | 42 | // Ensure unsafeck and abstract const building is ran before we steal the THIR. |
49aad941 FG |
43 | tcx.ensure_with_value().thir_check_unsafety(def); |
44 | tcx.ensure_with_value().thir_abstract_const(def); | |
45 | if let Err(e) = tcx.check_match(def) { | |
46 | return construct_error(tcx, def, e); | |
17df50a5 XL |
47 | } |
48 | ||
f2b60f7d | 49 | let body = match tcx.thir_body(def) { |
49aad941 | 50 | Err(error_reported) => construct_error(tcx, def, error_reported), |
f2b60f7d | 51 | Ok((thir, expr)) => { |
17df50a5 XL |
52 | // We ran all queries that depended on THIR at the beginning |
53 | // of `mir_build`, so now we can steal it | |
54 | let thir = thir.steal(); | |
ea8adc8c | 55 | |
49aad941 FG |
56 | tcx.ensure().check_match(def); |
57 | // this must run before MIR dump, because | |
58 | // "not all control paths return a value" is reported here. | |
59 | // | |
60 | // maybe move the check to a MIR pass? | |
61 | tcx.ensure().check_liveness(def); | |
62 | ||
9ffffee4 FG |
63 | match thir.body_type { |
64 | thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig), | |
65 | thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty), | |
6a06907d | 66 | } |
f2b60f7d FG |
67 | } |
68 | }; | |
7cac9316 | 69 | |
f2b60f7d FG |
70 | lints::check(tcx, &body); |
71 | ||
72 | // The borrow checker will replace all the regions here with its own | |
73 | // inference variables. There's no point having non-erased regions here. | |
74 | // The exception is `body.user_type_annotations`, which is used unmodified | |
75 | // by borrow checking. | |
76 | debug_assert!( | |
77 | !(body.local_decls.has_free_regions() | |
78 | || body.basic_blocks.has_free_regions() | |
79 | || body.var_debug_info.has_free_regions() | |
80 | || body.yield_ty().has_free_regions()), | |
81 | "Unexpected free regions in MIR: {:?}", | |
82 | body, | |
83 | ); | |
ba9703b0 | 84 | |
f2b60f7d | 85 | body |
7cac9316 XL |
86 | } |
87 | ||
7cac9316 XL |
88 | /////////////////////////////////////////////////////////////////////////// |
89 | // BuildMir -- walks a crate, looking for fn items and methods to build MIR from | |
90 | ||
0bf4aa26 | 91 | #[derive(Debug, PartialEq, Eq)] |
dfeec247 | 92 | enum BlockFrame { |
0bf4aa26 XL |
93 | /// Evaluation is currently within a statement. |
94 | /// | |
95 | /// Examples include: | |
dc9dc135 XL |
96 | /// 1. `EXPR;` |
97 | /// 2. `let _ = EXPR;` | |
98 | /// 3. `let x = EXPR;` | |
0bf4aa26 XL |
99 | Statement { |
100 | /// If true, then statement discards result from evaluating | |
101 | /// the expression (such as examples 1 and 2 above). | |
dfeec247 | 102 | ignores_expr_result: bool, |
0bf4aa26 XL |
103 | }, |
104 | ||
105 | /// Evaluation is currently within the tail expression of a block. | |
106 | /// | |
107 | /// Example: `{ STMT_1; STMT_2; EXPR }` | |
108 | TailExpr { | |
109 | /// If true, then the surrounding context of the block ignores | |
110 | /// the result of evaluating the block's tail expression. | |
111 | /// | |
112 | /// Example: `let _ = { STMT_1; EXPR };` | |
dfeec247 | 113 | tail_result_is_ignored: bool, |
f9f354fc XL |
114 | |
115 | /// `Span` of the tail expression. | |
116 | span: Span, | |
0bf4aa26 XL |
117 | }, |
118 | ||
119 | /// Generic mark meaning that the block occurred as a subexpression | |
120 | /// where the result might be used. | |
121 | /// | |
122 | /// Examples: `foo(EXPR)`, `match EXPR { ... }` | |
123 | SubExpr, | |
124 | } | |
125 | ||
126 | impl BlockFrame { | |
127 | fn is_tail_expr(&self) -> bool { | |
128 | match *self { | |
129 | BlockFrame::TailExpr { .. } => true, | |
130 | ||
dfeec247 | 131 | BlockFrame::Statement { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
132 | } |
133 | } | |
134 | fn is_statement(&self) -> bool { | |
135 | match *self { | |
136 | BlockFrame::Statement { .. } => true, | |
137 | ||
dfeec247 | 138 | BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false, |
0bf4aa26 XL |
139 | } |
140 | } | |
dfeec247 | 141 | } |
0bf4aa26 | 142 | |
a1dfa0c6 XL |
143 | #[derive(Debug)] |
144 | struct BlockContext(Vec<BlockFrame>); | |
145 | ||
dc9dc135 | 146 | struct Builder<'a, 'tcx> { |
6a06907d | 147 | tcx: TyCtxt<'tcx>, |
2b03887a | 148 | infcx: InferCtxt<'tcx>, |
6a06907d XL |
149 | region_scope_tree: &'tcx region::ScopeTree, |
150 | param_env: ty::ParamEnv<'tcx>, | |
151 | ||
17df50a5 | 152 | thir: &'a Thir<'tcx>, |
b039eaaf | 153 | cfg: CFG<'tcx>, |
54a0048b | 154 | |
49aad941 | 155 | def_id: LocalDefId, |
6a06907d | 156 | hir_id: hir::HirId, |
04454e1e | 157 | parent_module: DefId, |
6a06907d | 158 | check_overflow: bool, |
54a0048b | 159 | fn_span: Span, |
c30ab7b3 | 160 | arg_count: usize, |
60c5eb7d | 161 | generator_kind: Option<GeneratorKind>, |
54a0048b | 162 | |
9fa01778 XL |
163 | /// The current set of scopes, updated as we traverse; |
164 | /// see the `scope` module for more details. | |
dc9dc135 | 165 | scopes: scope::Scopes<'tcx>, |
54a0048b | 166 | |
3dfed10e | 167 | /// The block-context: each time we build the code within an thir::Block, |
0bf4aa26 XL |
168 | /// we push a frame here tracking whether we are building a statement or |
169 | /// if we are pushing the tail expression of the block. This is used to | |
170 | /// embed information in generated temps about whether they were created | |
171 | /// for a block tail expression or not. | |
172 | /// | |
173 | /// It would be great if we could fold this into `self.scopes` | |
9fa01778 | 174 | /// somehow, but right now I think that is very tightly tied to |
0bf4aa26 XL |
175 | /// the code generation in ways that we cannot (or should not) |
176 | /// start just throwing new entries onto that vector in order to | |
177 | /// distinguish the context of EXPR1 from the context of EXPR2 in | |
9fa01778 | 178 | /// `{ STMTS; EXPR1 } + EXPR2`. |
a1dfa0c6 | 179 | block_context: BlockContext, |
0bf4aa26 | 180 | |
136023e0 XL |
181 | /// The current unsafe block in scope |
182 | in_scope_unsafe: Safety, | |
ea8adc8c | 183 | |
9fa01778 XL |
184 | /// The vector of all scopes that we have created thus far; |
185 | /// we track this for debuginfo later. | |
29967ef6 | 186 | source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, |
94b46f34 | 187 | source_scope: SourceScope, |
54a0048b | 188 | |
9fa01778 | 189 | /// The guard-context: each time we build the guard expression for |
83c7162d XL |
190 | /// a match arm, we push onto this stack, and then pop when we |
191 | /// finish building it. | |
192 | guard_context: Vec<GuardFrame>, | |
193 | ||
532ac7d7 | 194 | /// Maps `HirId`s of variable bindings to the `Local`s created for them. |
83c7162d | 195 | /// (A match binding can have two locals; the 2nd is for the arm's guard.) |
923072b8 | 196 | var_indices: FxHashMap<LocalVarId, LocalsForNode>, |
c30ab7b3 | 197 | local_decls: IndexVec<Local, LocalDecl<'tcx>>, |
0731742a | 198 | canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, |
f2b60f7d | 199 | upvars: CaptureMap<'tcx>, |
ff7c6d11 | 200 | unit_temp: Option<Place<'tcx>>, |
54a0048b | 201 | |
60c5eb7d | 202 | var_debug_info: Vec<VarDebugInfo<'tcx>>, |
e9174d1e SL |
203 | } |
204 | ||
f2b60f7d FG |
205 | type CaptureMap<'tcx> = SortedIndexMultiMap<usize, hir::HirId, Capture<'tcx>>; |
206 | ||
207 | #[derive(Debug)] | |
208 | struct Capture<'tcx> { | |
209 | captured_place: &'tcx ty::CapturedPlace<'tcx>, | |
210 | use_place: Place<'tcx>, | |
211 | mutability: Mutability, | |
212 | } | |
213 | ||
dc9dc135 | 214 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
923072b8 | 215 | fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool { |
83c7162d XL |
216 | self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id)) |
217 | } | |
218 | ||
923072b8 | 219 | fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local { |
83c7162d XL |
220 | self.var_indices[&id].local_id(for_guard) |
221 | } | |
222 | } | |
223 | ||
a1dfa0c6 | 224 | impl BlockContext { |
dfeec247 XL |
225 | fn new() -> Self { |
226 | BlockContext(vec![]) | |
227 | } | |
228 | fn push(&mut self, bf: BlockFrame) { | |
229 | self.0.push(bf); | |
230 | } | |
231 | fn pop(&mut self) -> Option<BlockFrame> { | |
232 | self.0.pop() | |
233 | } | |
a1dfa0c6 | 234 | |
9fa01778 | 235 | /// Traverses the frames on the `BlockContext`, searching for either |
a1dfa0c6 XL |
236 | /// the first block-tail expression frame with no intervening |
237 | /// statement frame. | |
238 | /// | |
239 | /// Notably, this skips over `SubExpr` frames; this method is | |
240 | /// meant to be used in the context of understanding the | |
241 | /// relationship of a temp (created within some complicated | |
242 | /// expression) with its containing expression, and whether the | |
243 | /// value of that *containing expression* (not the temp!) is | |
244 | /// ignored. | |
245 | fn currently_in_block_tail(&self) -> Option<BlockTailInfo> { | |
246 | for bf in self.0.iter().rev() { | |
247 | match bf { | |
248 | BlockFrame::SubExpr => continue, | |
249 | BlockFrame::Statement { .. } => break, | |
f9f354fc XL |
250 | &BlockFrame::TailExpr { tail_result_is_ignored, span } => { |
251 | return Some(BlockTailInfo { tail_result_is_ignored, span }); | |
dfeec247 | 252 | } |
a1dfa0c6 XL |
253 | } |
254 | } | |
255 | ||
ba9703b0 | 256 | None |
a1dfa0c6 XL |
257 | } |
258 | ||
259 | /// Looks at the topmost frame on the BlockContext and reports | |
260 | /// whether its one that would discard a block tail result. | |
261 | /// | |
262 | /// Unlike `currently_within_ignored_tail_expression`, this does | |
263 | /// *not* skip over `SubExpr` frames: here, we want to know | |
264 | /// whether the block result itself is discarded. | |
265 | fn currently_ignores_tail_results(&self) -> bool { | |
266 | match self.0.last() { | |
267 | // no context: conservatively assume result is read | |
268 | None => false, | |
269 | ||
270 | // sub-expression: block result feeds into some computation | |
271 | Some(BlockFrame::SubExpr) => false, | |
272 | ||
273 | // otherwise: use accumulated is_ignored state. | |
ba9703b0 | 274 | Some( |
f9f354fc | 275 | BlockFrame::TailExpr { tail_result_is_ignored: ignored, .. } |
ba9703b0 XL |
276 | | BlockFrame::Statement { ignores_expr_result: ignored }, |
277 | ) => *ignored, | |
a1dfa0c6 XL |
278 | } |
279 | } | |
280 | } | |
281 | ||
83c7162d XL |
282 | #[derive(Debug)] |
283 | enum LocalsForNode { | |
532ac7d7 | 284 | /// In the usual case, a `HirId` for an identifier maps to at most |
9fa01778 | 285 | /// one `Local` declaration. |
83c7162d | 286 | One(Local), |
8faf50e0 XL |
287 | |
288 | /// The exceptional case is identifiers in a match arm's pattern | |
289 | /// that are referenced in a guard of that match arm. For these, | |
9fa01778 | 290 | /// we have `2` Locals. |
8faf50e0 XL |
291 | /// |
292 | /// * `for_arm_body` is the Local used in the arm body (which is | |
293 | /// just like the `One` case above), | |
294 | /// | |
295 | /// * `ref_for_guard` is the Local used in the arm's guard (which | |
296 | /// is a reference to a temp that is an alias of | |
297 | /// `for_arm_body`). | |
9fa01778 | 298 | ForGuard { ref_for_guard: Local, for_arm_body: Local }, |
83c7162d XL |
299 | } |
300 | ||
301 | #[derive(Debug)] | |
302 | struct GuardFrameLocal { | |
923072b8 | 303 | id: LocalVarId, |
83c7162d XL |
304 | } |
305 | ||
306 | impl GuardFrameLocal { | |
923072b8 | 307 | fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self { |
74b04a01 | 308 | GuardFrameLocal { id } |
83c7162d XL |
309 | } |
310 | } | |
311 | ||
312 | #[derive(Debug)] | |
313 | struct GuardFrame { | |
314 | /// These are the id's of names that are bound by patterns of the | |
315 | /// arm of *this* guard. | |
316 | /// | |
317 | /// (Frames higher up the stack will have the id's bound in arms | |
318 | /// further out, such as in a case like: | |
319 | /// | |
320 | /// match E1 { | |
321 | /// P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1, | |
322 | /// } | |
323 | /// | |
9fa01778 | 324 | /// here, when building for FIXME. |
83c7162d XL |
325 | locals: Vec<GuardFrameLocal>, |
326 | } | |
327 | ||
9fa01778 XL |
328 | /// `ForGuard` indicates whether we are talking about: |
329 | /// 1. The variable for use outside of guard expressions, or | |
330 | /// 2. The temp that holds reference to (1.), which is actually what the | |
331 | /// guard expressions see. | |
83c7162d XL |
332 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
333 | enum ForGuard { | |
94b46f34 | 334 | RefWithinGuard, |
83c7162d XL |
335 | OutsideGuard, |
336 | } | |
337 | ||
338 | impl LocalsForNode { | |
339 | fn local_id(&self, for_guard: ForGuard) -> Local { | |
340 | match (self, for_guard) { | |
dfeec247 XL |
341 | (&LocalsForNode::One(local_id), ForGuard::OutsideGuard) |
342 | | ( | |
343 | &LocalsForNode::ForGuard { ref_for_guard: local_id, .. }, | |
344 | ForGuard::RefWithinGuard, | |
345 | ) | |
346 | | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => { | |
347 | local_id | |
348 | } | |
83c7162d | 349 | |
dfeec247 XL |
350 | (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => { |
351 | bug!("anything with one local should never be within a guard.") | |
352 | } | |
83c7162d XL |
353 | } |
354 | } | |
355 | } | |
356 | ||
b039eaaf | 357 | struct CFG<'tcx> { |
3157f602 XL |
358 | basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, |
359 | } | |
360 | ||
e74abb32 | 361 | rustc_index::newtype_index! { |
9c376795 | 362 | struct ScopeId {} |
b7449926 | 363 | } |
e9174d1e | 364 | |
04454e1e FG |
365 | #[derive(Debug)] |
366 | enum NeedsTemporary { | |
367 | /// Use this variant when whatever you are converting with `as_operand` | |
368 | /// is the last thing you are converting. This means that if we introduced | |
369 | /// an intermediate temporary, we'd only read it immediately after, so we can | |
370 | /// also avoid it. | |
371 | No, | |
372 | /// For all cases where you aren't sure or that are too expensive to compute | |
373 | /// for now. It is always safe to fall back to this. | |
374 | Maybe, | |
375 | } | |
376 | ||
e9174d1e | 377 | /////////////////////////////////////////////////////////////////////////// |
7453a54e SL |
378 | /// The `BlockAnd` "monad" packages up the new basic block along with a |
379 | /// produced value (sometimes just unit, of course). The `unpack!` | |
380 | /// macro (and methods below) makes working with `BlockAnd` much more | |
381 | /// convenient. | |
e9174d1e | 382 | |
83c7162d | 383 | #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] |
7cac9316 | 384 | struct BlockAnd<T>(BasicBlock, T); |
e9174d1e | 385 | |
92a42be0 SL |
386 | trait BlockAndExtension { |
387 | fn and<T>(self, v: T) -> BlockAnd<T>; | |
388 | fn unit(self) -> BlockAnd<()>; | |
389 | } | |
390 | ||
391 | impl BlockAndExtension for BasicBlock { | |
e9174d1e SL |
392 | fn and<T>(self, v: T) -> BlockAnd<T> { |
393 | BlockAnd(self, v) | |
394 | } | |
395 | ||
396 | fn unit(self) -> BlockAnd<()> { | |
397 | BlockAnd(self, ()) | |
398 | } | |
399 | } | |
400 | ||
401 | /// Update a block pointer and return the value. | |
402 | /// Use it like `let x = unpack!(block = self.foo(block, foo))`. | |
403 | macro_rules! unpack { | |
dfeec247 XL |
404 | ($x:ident = $c:expr) => {{ |
405 | let BlockAnd(b, v) = $c; | |
406 | $x = b; | |
407 | v | |
408 | }}; | |
409 | ||
410 | ($c:expr) => {{ | |
411 | let BlockAnd(b, ()) = $c; | |
412 | b | |
413 | }}; | |
e9174d1e SL |
414 | } |
415 | ||
416 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e | 417 | /// the main entry point for building MIR for a function |
e9174d1e | 418 | |
f2b60f7d FG |
419 | fn construct_fn<'tcx>( |
420 | tcx: TyCtxt<'tcx>, | |
49aad941 | 421 | fn_def: LocalDefId, |
f2b60f7d | 422 | thir: &Thir<'tcx>, |
17df50a5 | 423 | expr: ExprId, |
9ffffee4 | 424 | fn_sig: ty::FnSig<'tcx>, |
f2b60f7d | 425 | ) -> Body<'tcx> { |
49aad941 FG |
426 | let span = tcx.def_span(fn_def); |
427 | let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def); | |
428 | let generator_kind = tcx.generator_kind(fn_def); | |
ea8adc8c | 429 | |
9ffffee4 FG |
430 | // The representation of thir for `-Zunpretty=thir-tree` relies on |
431 | // the entry expression being the last element of `thir.exprs`. | |
432 | assert_eq!(expr.as_usize(), thir.exprs.len() - 1); | |
433 | ||
f2b60f7d | 434 | // Figure out what primary body this item has. |
49aad941 | 435 | let body_id = tcx.hir().body_owned_by(fn_def); |
f2b60f7d FG |
436 | let span_with_body = tcx.hir().span_with_body(fn_id); |
437 | let return_ty_span = tcx | |
438 | .hir() | |
439 | .fn_decl_by_hir_id(fn_id) | |
49aad941 | 440 | .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def)) |
f2b60f7d FG |
441 | .output |
442 | .span(); | |
443 | ||
f2b60f7d FG |
444 | let safety = match fn_sig.unsafety { |
445 | hir::Unsafety::Normal => Safety::Safe, | |
446 | hir::Unsafety::Unsafe => Safety::FnUnsafe, | |
447 | }; | |
448 | ||
449 | let mut abi = fn_sig.abi; | |
49aad941 | 450 | if let DefKind::Closure = tcx.def_kind(fn_def) { |
f2b60f7d FG |
451 | // HACK(eddyb) Avoid having RustCall on closures, |
452 | // as it adds unnecessary (and wrong) auto-tupling. | |
453 | abi = Abi::Rust; | |
454 | } | |
455 | ||
456 | let arguments = &thir.params; | |
457 | ||
458 | let (yield_ty, return_ty) = if generator_kind.is_some() { | |
459 | let gen_ty = arguments[thir::UPVAR_ENV_PARAM].ty; | |
460 | let gen_sig = match gen_ty.kind() { | |
461 | ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(), | |
462 | _ => { | |
463 | span_bug!(span, "generator w/o generator type: {:?}", gen_ty) | |
464 | } | |
465 | }; | |
466 | (Some(gen_sig.yield_ty), gen_sig.return_ty) | |
467 | } else { | |
468 | (None, fn_sig.output()) | |
469 | }; | |
a7813a04 | 470 | |
487cf647 FG |
471 | if let Some(custom_mir_attr) = |
472 | tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir) | |
473 | { | |
474 | return custom::build_custom_mir( | |
475 | tcx, | |
49aad941 | 476 | fn_def.to_def_id(), |
9c376795 | 477 | fn_id, |
487cf647 FG |
478 | thir, |
479 | expr, | |
480 | arguments, | |
481 | return_ty, | |
482 | return_ty_span, | |
483 | span_with_body, | |
484 | custom_mir_attr, | |
485 | ); | |
486 | } | |
487 | ||
2b03887a FG |
488 | let infcx = tcx.infer_ctxt().build(); |
489 | let mut builder = Builder::new( | |
490 | thir, | |
491 | infcx, | |
492 | fn_def, | |
493 | fn_id, | |
494 | span_with_body, | |
495 | arguments.len(), | |
496 | safety, | |
497 | return_ty, | |
498 | return_ty_span, | |
499 | generator_kind, | |
500 | ); | |
501 | ||
502 | let call_site_scope = | |
503 | region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite }; | |
504 | let arg_scope = | |
505 | region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments }; | |
506 | let source_info = builder.source_info(span); | |
507 | let call_site_s = (call_site_scope, source_info); | |
508 | unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { | |
509 | let arg_scope_s = (arg_scope, source_info); | |
510 | // Attribute epilogue to function's closing brace | |
511 | let fn_end = span_with_body.shrink_to_hi(); | |
512 | let return_block = | |
513 | unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { | |
514 | Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { | |
9ffffee4 | 515 | builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr]) |
2b03887a FG |
516 | })) |
517 | })); | |
518 | let source_info = builder.source_info(fn_end); | |
519 | builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); | |
520 | builder.build_drop_trees(); | |
521 | return_block.unit() | |
522 | })); | |
523 | ||
524 | let mut body = builder.finish(); | |
f2b60f7d FG |
525 | |
526 | body.spread_arg = if abi == Abi::RustCall { | |
476ff2be | 527 | // RustCall pseudo-ABI untuples the last argument. |
ba9703b0 XL |
528 | Some(Local::new(arguments.len())) |
529 | } else { | |
530 | None | |
531 | }; | |
f2b60f7d FG |
532 | if yield_ty.is_some() { |
533 | body.generator.as_mut().unwrap().yield_ty = yield_ty; | |
534 | } | |
dc9dc135 | 535 | body |
a7813a04 XL |
536 | } |
537 | ||
dc9dc135 | 538 | fn construct_const<'a, 'tcx>( |
f2b60f7d | 539 | tcx: TyCtxt<'tcx>, |
49aad941 | 540 | def: LocalDefId, |
17df50a5 | 541 | thir: &'a Thir<'tcx>, |
17df50a5 | 542 | expr: ExprId, |
9ffffee4 | 543 | const_ty: Ty<'tcx>, |
dc9dc135 | 544 | ) -> Body<'tcx> { |
49aad941 | 545 | let hir_id = tcx.hir().local_def_id_to_hir_id(def); |
a7813a04 | 546 | |
f2b60f7d FG |
547 | // Figure out what primary body this item has. |
548 | let (span, const_ty_span) = match tcx.hir().get(hir_id) { | |
549 | Node::Item(hir::Item { | |
550 | kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _), | |
551 | span, | |
552 | .. | |
553 | }) | |
554 | | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. }) | |
555 | | Node::TraitItem(hir::TraitItem { | |
556 | kind: hir::TraitItemKind::Const(ty, Some(_)), | |
557 | span, | |
558 | .. | |
559 | }) => (*span, ty.span), | |
560 | Node::AnonConst(_) => { | |
49aad941 | 561 | let span = tcx.def_span(def); |
f2b60f7d FG |
562 | (span, span) |
563 | } | |
49aad941 | 564 | _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), |
f2b60f7d | 565 | }; |
a7813a04 | 566 | |
2b03887a FG |
567 | let infcx = tcx.infer_ctxt().build(); |
568 | let mut builder = Builder::new( | |
569 | thir, | |
570 | infcx, | |
571 | def, | |
572 | hir_id, | |
573 | span, | |
574 | 0, | |
575 | Safety::Safe, | |
576 | const_ty, | |
577 | const_ty_span, | |
578 | None, | |
579 | ); | |
f2b60f7d | 580 | |
2b03887a FG |
581 | let mut block = START_BLOCK; |
582 | unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); | |
f2b60f7d | 583 | |
2b03887a FG |
584 | let source_info = builder.source_info(span); |
585 | builder.cfg.terminate(block, source_info, TerminatorKind::Return); | |
f2b60f7d | 586 | |
2b03887a | 587 | builder.build_drop_trees(); |
ff7c6d11 | 588 | |
2b03887a | 589 | builder.finish() |
e9174d1e SL |
590 | } |
591 | ||
94222f64 | 592 | /// Construct MIR for an item that has had errors in type checking. |
74b04a01 XL |
593 | /// |
594 | /// This is required because we may still want to run MIR passes on an item | |
595 | /// with type errors, but normal MIR construction can't handle that in general. | |
9ffffee4 | 596 | fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> { |
f2b60f7d FG |
597 | let span = tcx.def_span(def); |
598 | let hir_id = tcx.hir().local_def_id_to_hir_id(def); | |
599 | let generator_kind = tcx.generator_kind(def); | |
9ffffee4 | 600 | let body_owner_kind = tcx.hir().body_owner_kind(def); |
f2b60f7d | 601 | |
9ffffee4 | 602 | let ty = tcx.ty_error(err); |
6a06907d | 603 | let num_params = match body_owner_kind { |
9ffffee4 | 604 | hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(), |
74b04a01 | 605 | hir::BodyOwnerKind::Closure => { |
9ffffee4 | 606 | let ty = tcx.type_of(def).subst_identity(); |
f2b60f7d FG |
607 | match ty.kind() { |
608 | ty::Closure(_, substs) => { | |
609 | 1 + substs.as_closure().sig().inputs().skip_binder().len() | |
610 | } | |
611 | ty::Generator(..) => 2, | |
612 | _ => bug!("expected closure or generator, found {ty:?}"), | |
74b04a01 XL |
613 | } |
614 | } | |
615 | hir::BodyOwnerKind::Const => 0, | |
616 | hir::BodyOwnerKind::Static(_) => 0, | |
617 | }; | |
17df50a5 XL |
618 | let mut cfg = CFG { basic_blocks: IndexVec::new() }; |
619 | let mut source_scopes = IndexVec::new(); | |
620 | let mut local_decls = IndexVec::from_elem_n(LocalDecl::new(ty, span), 1); | |
621 | ||
622 | cfg.start_new_block(); | |
623 | source_scopes.push(SourceScopeData { | |
624 | span, | |
625 | parent_scope: None, | |
626 | inlined: None, | |
627 | inlined_parent_scope: None, | |
628 | local_data: ClearCrossCrate::Set(SourceScopeLocalData { | |
629 | lint_root: hir_id, | |
630 | safety: Safety::Safe, | |
631 | }), | |
632 | }); | |
633 | let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; | |
634 | ||
74b04a01 XL |
635 | // Some MIR passes will expect the number of parameters to match the |
636 | // function declaration. | |
637 | for _ in 0..num_params { | |
17df50a5 | 638 | local_decls.push(LocalDecl::with_source_info(ty, source_info)); |
74b04a01 | 639 | } |
17df50a5 XL |
640 | cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); |
641 | ||
642 | let mut body = Body::new( | |
f2b60f7d | 643 | MirSource::item(def.to_def_id()), |
17df50a5 XL |
644 | cfg.basic_blocks, |
645 | source_scopes, | |
646 | local_decls, | |
647 | IndexVec::new(), | |
648 | num_params, | |
649 | vec![], | |
650 | span, | |
651 | generator_kind, | |
5099ac24 | 652 | Some(err), |
17df50a5 | 653 | ); |
6a06907d | 654 | body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty)); |
74b04a01 | 655 | body |
8bb4bdeb XL |
656 | } |
657 | ||
dc9dc135 | 658 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
dfeec247 | 659 | fn new( |
17df50a5 | 660 | thir: &'a Thir<'tcx>, |
2b03887a | 661 | infcx: InferCtxt<'tcx>, |
49aad941 | 662 | def: LocalDefId, |
6a06907d | 663 | hir_id: hir::HirId, |
dfeec247 XL |
664 | span: Span, |
665 | arg_count: usize, | |
666 | safety: Safety, | |
667 | return_ty: Ty<'tcx>, | |
668 | return_span: Span, | |
669 | generator_kind: Option<GeneratorKind>, | |
670 | ) -> Builder<'a, 'tcx> { | |
6a06907d XL |
671 | let tcx = infcx.tcx; |
672 | let attrs = tcx.hir().attrs(hir_id); | |
673 | // Some functions always have overflow checks enabled, | |
674 | // however, they may not get codegen'd, depending on | |
675 | // the settings for the crate they are codegened in. | |
353b0b11 | 676 | let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); |
6a06907d XL |
677 | // Respect -C overflow-checks. |
678 | check_overflow |= tcx.sess.overflow_checks(); | |
679 | // Constants always need overflow checks. | |
680 | check_overflow |= matches!( | |
49aad941 | 681 | tcx.hir().body_owner_kind(def), |
6a06907d XL |
682 | hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) |
683 | ); | |
684 | ||
685 | let lint_level = LintLevel::Explicit(hir_id); | |
49aad941 | 686 | let param_env = tcx.param_env(def); |
a7813a04 | 687 | let mut builder = Builder { |
17df50a5 | 688 | thir, |
6a06907d XL |
689 | tcx, |
690 | infcx, | |
49aad941 | 691 | region_scope_tree: tcx.region_scope_tree(def), |
04454e1e | 692 | param_env, |
49aad941 | 693 | def_id: def, |
6a06907d | 694 | hir_id, |
04454e1e | 695 | parent_module: tcx.parent_module(hir_id).to_def_id(), |
6a06907d | 696 | check_overflow, |
3157f602 | 697 | cfg: CFG { basic_blocks: IndexVec::new() }, |
a7813a04 | 698 | fn_span: span, |
3b2f2976 | 699 | arg_count, |
60c5eb7d | 700 | generator_kind, |
29967ef6 | 701 | scopes: scope::Scopes::new(), |
a1dfa0c6 | 702 | block_context: BlockContext::new(), |
94b46f34 XL |
703 | source_scopes: IndexVec::new(), |
704 | source_scope: OUTERMOST_SOURCE_SCOPE, | |
83c7162d | 705 | guard_context: vec![], |
136023e0 | 706 | in_scope_unsafe: safety, |
f9f354fc | 707 | local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1), |
0731742a | 708 | canonical_user_type_annotations: IndexVec::new(), |
f2b60f7d | 709 | upvars: CaptureMap::new(), |
a1dfa0c6 | 710 | var_indices: Default::default(), |
a7813a04 | 711 | unit_temp: None, |
60c5eb7d | 712 | var_debug_info: vec![], |
a7813a04 XL |
713 | }; |
714 | ||
715 | assert_eq!(builder.cfg.start_new_block(), START_BLOCK); | |
ea8adc8c | 716 | assert_eq!( |
94b46f34 | 717 | builder.new_source_scope(span, lint_level, Some(safety)), |
dfeec247 XL |
718 | OUTERMOST_SOURCE_SCOPE |
719 | ); | |
94b46f34 | 720 | builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None; |
a7813a04 XL |
721 | |
722 | builder | |
723 | } | |
724 | ||
60c5eb7d | 725 | fn finish(self) -> Body<'tcx> { |
a7813a04 XL |
726 | for (index, block) in self.cfg.basic_blocks.iter().enumerate() { |
727 | if block.terminator.is_none() { | |
728 | span_bug!(self.fn_span, "no terminator on block {:?}", index); | |
729 | } | |
730 | } | |
731 | ||
dc9dc135 | 732 | Body::new( |
49aad941 | 733 | MirSource::item(self.def_id.to_def_id()), |
0731742a XL |
734 | self.cfg.basic_blocks, |
735 | self.source_scopes, | |
0731742a XL |
736 | self.local_decls, |
737 | self.canonical_user_type_annotations, | |
738 | self.arg_count, | |
60c5eb7d | 739 | self.var_debug_info, |
0731742a | 740 | self.fn_span, |
dfeec247 | 741 | self.generator_kind, |
9ffffee4 | 742 | None, |
476ff2be | 743 | ) |
a7813a04 XL |
744 | } |
745 | ||
9ffffee4 FG |
746 | fn insert_upvar_arg(&mut self) { |
747 | let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return }; | |
748 | ||
749 | let mut closure_ty = closure_arg.ty; | |
750 | let mut closure_env_projs = vec![]; | |
751 | if let ty::Ref(_, ty, _) = closure_ty.kind() { | |
752 | closure_env_projs.push(ProjectionElem::Deref); | |
753 | closure_ty = *ty; | |
754 | } | |
755 | ||
756 | let upvar_substs = match closure_ty.kind() { | |
757 | ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), | |
758 | ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), | |
759 | _ => return, | |
760 | }; | |
761 | ||
762 | // In analyze_closure() in upvar.rs we gathered a list of upvars used by an | |
763 | // indexed closure and we stored in a map called closure_min_captures in TypeckResults | |
764 | // with the closure's DefId. Here, we run through that vec of UpvarIds for | |
765 | // the given closure and use the necessary information to create upvar | |
766 | // debuginfo and to fill `self.upvars`. | |
767 | let capture_tys = upvar_substs.upvar_tys(); | |
768 | ||
769 | let tcx = self.tcx; | |
770 | self.upvars = tcx | |
49aad941 | 771 | .closure_captures(self.def_id) |
9ffffee4 FG |
772 | .iter() |
773 | .zip(capture_tys) | |
774 | .enumerate() | |
775 | .map(|(i, (captured_place, ty))| { | |
776 | let name = captured_place.to_symbol(); | |
777 | ||
778 | let capture = captured_place.info.capture_kind; | |
779 | let var_id = match captured_place.place.base { | |
780 | HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, | |
781 | _ => bug!("Expected an upvar"), | |
782 | }; | |
783 | ||
784 | let mutability = captured_place.mutability; | |
785 | ||
786 | let mut projs = closure_env_projs.clone(); | |
353b0b11 | 787 | projs.push(ProjectionElem::Field(FieldIdx::new(i), ty)); |
9ffffee4 FG |
788 | match capture { |
789 | ty::UpvarCapture::ByValue => {} | |
790 | ty::UpvarCapture::ByRef(..) => { | |
791 | projs.push(ProjectionElem::Deref); | |
792 | } | |
793 | }; | |
794 | ||
795 | let use_place = Place { | |
796 | local: ty::CAPTURE_STRUCT_LOCAL, | |
797 | projection: tcx.mk_place_elems(&projs), | |
798 | }; | |
799 | self.var_debug_info.push(VarDebugInfo { | |
800 | name, | |
49aad941 | 801 | references: 0, |
9ffffee4 FG |
802 | source_info: SourceInfo::outermost(captured_place.var_ident.span), |
803 | value: VarDebugInfoContents::Place(use_place), | |
353b0b11 | 804 | argument_index: None, |
9ffffee4 FG |
805 | }); |
806 | ||
807 | let capture = Capture { captured_place, use_place, mutability }; | |
808 | (var_id, capture) | |
809 | }) | |
810 | .collect(); | |
811 | } | |
812 | ||
dfeec247 XL |
813 | fn args_and_body( |
814 | &mut self, | |
815 | mut block: BasicBlock, | |
353b0b11 | 816 | arguments: &IndexSlice<ParamId, Param<'tcx>>, |
dfeec247 | 817 | argument_scope: region::Scope, |
17df50a5 | 818 | expr: &Expr<'tcx>, |
dfeec247 | 819 | ) -> BlockAnd<()> { |
c30ab7b3 | 820 | // Allocate locals for the function arguments |
353b0b11 | 821 | for (argument_index, param) in arguments.iter().enumerate() { |
f9f354fc | 822 | let source_info = |
f2b60f7d FG |
823 | SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span)); |
824 | let arg_local = | |
825 | self.local_decls.push(LocalDecl::with_source_info(param.ty, source_info)); | |
60c5eb7d XL |
826 | |
827 | // If this is a simple binding pattern, give debuginfo a nice name. | |
f2b60f7d | 828 | if let Some(ref pat) = param.pat && let Some(name) = pat.simple_ident() { |
5e7ed085 | 829 | self.var_debug_info.push(VarDebugInfo { |
f2b60f7d | 830 | name, |
5e7ed085 | 831 | source_info, |
49aad941 | 832 | references: 0, |
5e7ed085 | 833 | value: VarDebugInfoContents::Place(arg_local.into()), |
353b0b11 | 834 | argument_index: Some(argument_index as u16 + 1), |
5e7ed085 | 835 | }); |
60c5eb7d XL |
836 | } |
837 | } | |
838 | ||
9ffffee4 | 839 | self.insert_upvar_arg(); |
c30ab7b3 | 840 | |
3157f602 | 841 | let mut scope = None; |
c30ab7b3 | 842 | // Bind the argument patterns |
f2b60f7d | 843 | for (index, param) in arguments.iter().enumerate() { |
ff7c6d11 | 844 | // Function arguments always get the first Local indices after the return place |
abe05a73 | 845 | let local = Local::new(index + 1); |
dc9dc135 | 846 | let place = Place::from(local); |
c30ab7b3 | 847 | |
0731742a XL |
848 | // Make sure we drop (parts of) the argument even when not matched on. |
849 | self.schedule_drop( | |
f2b60f7d | 850 | param.pat.as_ref().map_or(expr.span, |pat| pat.span), |
dfeec247 XL |
851 | argument_scope, |
852 | local, | |
853 | DropKind::Value, | |
0731742a XL |
854 | ); |
855 | ||
f2b60f7d | 856 | let Some(ref pat) = param.pat else { |
3c0e092e XL |
857 | continue; |
858 | }; | |
3c0e092e | 859 | let original_source_scope = self.source_scope; |
f2b60f7d FG |
860 | let span = pat.span; |
861 | if let Some(arg_hir_id) = param.hir_id { | |
862 | self.set_correct_source_scope_for_arg(arg_hir_id, original_source_scope, span); | |
863 | } | |
864 | match pat.kind { | |
3c0e092e XL |
865 | // Don't introduce extra copies for simple bindings |
866 | PatKind::Binding { | |
867 | mutability, | |
868 | var, | |
869 | mode: BindingMode::ByValue, | |
870 | subpattern: None, | |
871 | .. | |
872 | } => { | |
873 | self.local_decls[local].mutability = mutability; | |
874 | self.local_decls[local].source_info.scope = self.source_scope; | |
353b0b11 FG |
875 | **self.local_decls[local].local_info.as_mut().assert_crate_local() = |
876 | if let Some(kind) = param.self_kind { | |
877 | LocalInfo::User(BindingForm::ImplicitSelf(kind)) | |
878 | } else { | |
879 | let binding_mode = ty::BindingMode::BindByValue(mutability); | |
880 | LocalInfo::User(BindingForm::Var(VarBindingForm { | |
3c0e092e | 881 | binding_mode, |
f2b60f7d FG |
882 | opt_ty_info: param.ty_span, |
883 | opt_match_place: Some((None, span)), | |
3c0e092e | 884 | pat_span: span, |
353b0b11 FG |
885 | })) |
886 | }; | |
3c0e092e XL |
887 | self.var_indices.insert(var, LocalsForNode::One(local)); |
888 | } | |
889 | _ => { | |
890 | scope = self.declare_bindings( | |
891 | scope, | |
892 | expr.span, | |
f2b60f7d | 893 | &pat, |
487cf647 | 894 | None, |
3c0e092e XL |
895 | Some((Some(&place), span)), |
896 | ); | |
897 | let place_builder = PlaceBuilder::from(local); | |
f2b60f7d | 898 | unpack!(block = self.place_into_pattern(block, &pat, place_builder, false)); |
abe05a73 | 899 | } |
a7813a04 | 900 | } |
3c0e092e | 901 | self.source_scope = original_source_scope; |
c30ab7b3 | 902 | } |
a7813a04 | 903 | |
94b46f34 XL |
904 | // Enter the argument pattern bindings source scope, if it exists. |
905 | if let Some(source_scope) = scope { | |
906 | self.source_scope = source_scope; | |
3157f602 XL |
907 | } |
908 | ||
6a06907d | 909 | self.expr_into_dest(Place::return_place(), block, &expr) |
416331ca XL |
910 | } |
911 | ||
912 | fn set_correct_source_scope_for_arg( | |
913 | &mut self, | |
914 | arg_hir_id: hir::HirId, | |
915 | original_source_scope: SourceScope, | |
dfeec247 | 916 | pattern_span: Span, |
416331ca | 917 | ) { |
487cf647 FG |
918 | let parent_id = self.source_scopes[original_source_scope] |
919 | .local_data | |
920 | .as_ref() | |
921 | .assert_crate_local() | |
922 | .lint_root; | |
923 | self.maybe_new_source_scope(pattern_span, None, arg_hir_id, parent_id); | |
e9174d1e | 924 | } |
7453a54e | 925 | |
ff7c6d11 | 926 | fn get_unit_temp(&mut self) -> Place<'tcx> { |
7453a54e | 927 | match self.unit_temp { |
dfeec247 | 928 | Some(tmp) => tmp, |
7453a54e | 929 | None => { |
6a06907d | 930 | let ty = self.tcx.mk_unit(); |
cc61c64b XL |
931 | let fn_span = self.fn_span; |
932 | let tmp = self.temp(ty, fn_span); | |
dfeec247 | 933 | self.unit_temp = Some(tmp); |
7453a54e SL |
934 | tmp |
935 | } | |
936 | } | |
937 | } | |
e9174d1e SL |
938 | } |
939 | ||
923072b8 FG |
940 | fn parse_float_into_constval<'tcx>( |
941 | num: Symbol, | |
942 | float_ty: ty::FloatTy, | |
943 | neg: bool, | |
944 | ) -> Option<ConstValue<'tcx>> { | |
945 | parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar) | |
946 | } | |
947 | ||
948 | pub(crate) fn parse_float_into_scalar( | |
949 | num: Symbol, | |
950 | float_ty: ty::FloatTy, | |
951 | neg: bool, | |
952 | ) -> Option<Scalar> { | |
953 | let num = num.as_str(); | |
954 | match float_ty { | |
955 | ty::FloatTy::F32 => { | |
956 | let Ok(rust_f) = num.parse::<f32>() else { return None }; | |
957 | let mut f = num.parse::<Single>().unwrap_or_else(|e| { | |
958 | panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) | |
959 | }); | |
960 | ||
961 | assert!( | |
962 | u128::from(rust_f.to_bits()) == f.to_bits(), | |
963 | "apfloat::ieee::Single gave different result for `{}`: \ | |
964 | {}({:#x}) vs Rust's {}({:#x})", | |
965 | rust_f, | |
966 | f, | |
967 | f.to_bits(), | |
968 | Single::from_bits(rust_f.to_bits().into()), | |
969 | rust_f.to_bits() | |
970 | ); | |
971 | ||
972 | if neg { | |
973 | f = -f; | |
974 | } | |
975 | ||
976 | Some(Scalar::from_f32(f)) | |
977 | } | |
978 | ty::FloatTy::F64 => { | |
979 | let Ok(rust_f) = num.parse::<f64>() else { return None }; | |
980 | let mut f = num.parse::<Double>().unwrap_or_else(|e| { | |
981 | panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) | |
982 | }); | |
983 | ||
984 | assert!( | |
985 | u128::from(rust_f.to_bits()) == f.to_bits(), | |
986 | "apfloat::ieee::Double gave different result for `{}`: \ | |
987 | {}({:#x}) vs Rust's {}({:#x})", | |
988 | rust_f, | |
989 | f, | |
990 | f.to_bits(), | |
991 | Double::from_bits(rust_f.to_bits().into()), | |
992 | rust_f.to_bits() | |
993 | ); | |
994 | ||
995 | if neg { | |
996 | f = -f; | |
997 | } | |
998 | ||
999 | Some(Scalar::from_f64(f)) | |
1000 | } | |
1001 | } | |
1002 | } | |
1003 | ||
e9174d1e SL |
1004 | /////////////////////////////////////////////////////////////////////////// |
1005 | // Builder methods are broken up into modules, depending on what kind | |
94b46f34 | 1006 | // of thing is being lowered. Note that they use the `unpack` macro |
e9174d1e SL |
1007 | // above extensively. |
1008 | ||
1009 | mod block; | |
1010 | mod cfg; | |
487cf647 | 1011 | mod custom; |
e9174d1e | 1012 | mod expr; |
e9174d1e SL |
1013 | mod matches; |
1014 | mod misc; | |
1015 | mod scope; | |
136023e0 XL |
1016 | |
1017 | pub(crate) use expr::category::Category as ExprCategory; |