rust/compiler/rustc_mir_transform/src
bors 3c9faa0d03 Auto merge of #148190 - RalfJung:box_new, r=RalfJung
replace box_new with lower-level intrinsics

The `box_new` intrinsic is super special: during THIR construction it turns into an `ExprKind::Box` (formerly known as the `box` keyword), which then during MIR building turns into a special instruction sequence that invokes the exchange_malloc lang item (which has a name from a different time) and a special MIR statement to represent a shallowly-initialized `Box` (which raises [interesting opsem questions](https://github.com/rust-lang/rust/issues/97270)).

This PR is the n-th attempt to get rid of `box_new`. That's non-trivial because it usually causes a perf regression: replacing `box_new` by naive unsafe code will incur extra copies in debug builds, making the resulting binaries a lot slower, and will generate a lot more MIR, making compilation measurably slower. Furthermore, `vec!` is a macro, so the exact code it expands to is highly relevant for borrow checking, type inference, and temporary scopes.

To avoid those problems, this PR does its best to make the MIR almost exactly the same as what it was before. `box_new` is used in two places, `Box::new` and `vec!`:
- For `Box::new` that is fairly easy: the `move_by_value` intrinsic is basically all we need. However, to avoid the extra copy that would usually be generated for the argument of a function call, we need to special-case this intrinsic during MIR building. That's what the first commit does.
- `vec!` is a lot more tricky. As a macro, its details leak to stable code, so almost every variant I tried broke either type inference or the lifetimes of temporaries in some ui test or ended up accepting unsound code due to the borrow checker not enforcing all the constraints I hoped it would enforce. I ended up with a variant that involves a new intrinsic, `fn write_box_via_move<T>(b: Box<MaybeUninit<T>>, x: T) -> Box<MaybeUninit<T>>`, that writes a value into a `Box<MaybeUninit<T>>` and returns that box again. In exchange we can get rid of somewhat similar code in the lowering for `ExprKind::Box`, and the `exchange_malloc` lang item. (We can also get rid of `Rvalue::ShallowInitBox`; I didn't include that in this PR -- I think @cjgillot has a commit for this somewhere [around here](https://github.com/rust-lang/rust/pull/147862/commits).)

See [here](https://github.com/rust-lang/rust/pull/148190#issuecomment-3457454814) for the latest perf numbers. Most of the regressions are in deep-vector which consists entirely of an invocation of `vec!`, so any change to that macro affects this benchmark disproportionally.

This is my first time even looking at MIR building code, so I am very low confidence in that part of the patch, in particular when it comes to scopes and drops and things like that.

I also had do nerf some clippy tests because clippy gets confused by the new expansion of `vec!` so it makes fewer suggestions when `vec!` is involved.

### `vec!` FAQ

- Why does `write_box_via_move` return the `Box` again? Because we need to expand `vec!` to a bunch of method invocations without any blocks or let-statements, or else the temporary scopes (and type inference) don't work out.
- Why is `box_assume_init_into_vec_unsafe` (unsoundly!) a safe function? Because we can't use an unsafe block in `vec!` as that would necessarily also include the `$x` (due to it all being one big method invocation) and therefore interpret the user's code as being inside `unsafe`, which would be bad (and 10 years later, we still don't have safe blocks for macros like this).
- Why does `write_box_via_move` use `Box` as input/output type, and not, say, raw pointers? Because that is the only way to get the correct behavior when `$x` panics or has control effects: we need the `Box` to be dropped in that case. (As a nice side-effect this also makes the intrinsic safe, which is imported as explained in the previous bullet.)
- Can't we make it safe by having `write_box_via_move` return `Box<T>`? Yes we could, but there's no easy way for the intrinsic to convert its `Box<MaybeUninit<T>>` to a `Box<T>`. Transmuting would be unsound as the borrow checker would no longer properly enforce that lifetimes involved in a `vec!` invocation behave correctly.
- Is this macro truly cursed? Yes, yes it is.
2026-02-16 18:46:10 +00:00
..
coroutine Only load pin field once. 2025-10-24 02:41:50 +00:00
coverage coverage: Add a test case for a previously-unknown span mismatch 2026-02-03 22:53:38 +11:00
inline Make inliner cycle detection a fallible process 2025-12-30 22:01:49 -05:00
shim remove DerefTemp and CopyFromDeref from runtime mir 2025-10-06 10:57:27 -07:00
abort_unwinding_calls.rs Skip cleanups on unsupported targets 2025-09-11 16:13:32 -07:00
add_call_guards.rs Refactor AddCallGuards in two loops. 2025-10-08 19:44:56 +00:00
add_moves_for_packed_drops.rs show packed alignment in mir_transform_unaligned_packed_ref 2025-11-07 13:57:37 -07:00
add_retag.rs Remove Retag for Unique 2025-07-21 08:08:41 +00:00
add_subtyping_projections.rs ProjectionElem::Subtype -> CastKind::Subtype 2025-09-26 01:25:26 -07:00
check_alignment.rs Replace NullOp::SizeOf and NullOp::AlignOf by lang items. 2025-10-23 00:38:28 +00:00
check_call_recursion.rs Split impl_(opt_)trait_ref 2025-10-17 08:36:34 -05:00
check_const_item_mutation.rs Only look at trait impls in the current crate when looking for Drop impls 2025-04-02 07:30:11 +00:00
check_enums.rs Fix ICE when validating transmuting ZST to inhabited enum 2025-08-23 19:25:58 +02:00
check_inline.rs Port rustc_no_mir_inline to the new attribute parser 2026-02-10 10:25:19 +01:00
check_inline_always_target_features.rs inline at the callsite & warn when target features mismatch 2025-08-27 14:45:01 +01:00
check_null.rs Replace NullOp::SizeOf and NullOp::AlignOf by lang items. 2025-10-23 00:38:28 +00:00
check_packed_ref.rs show packed alignment in mir_transform_unaligned_packed_ref 2025-11-07 13:57:37 -07:00
check_pointers.rs mir: Use the new method for BasicBlockData 2025-06-29 20:39:13 +08:00
cleanup_post_borrowck.rs Stop invalidating in CleanupPostBorrowck. 2025-10-20 21:34:46 +00:00
copy_prop.rs Turn moves into copies after copy propagation 2025-11-20 19:23:10 +01:00
coroutine.rs Port #[must_not_suspend] to attribute parser 2026-01-12 18:16:37 +01:00
cost_checker.rs Reinstate bonus for unused UbChecks. 2025-12-21 00:58:00 +00:00
cross_crate_inline.rs Port rustc_intrinsic to the new attribute parser 2026-02-07 14:12:56 +01:00
ctfe_limit.rs Do not invalidate CFG caches in CtfeLimit. 2025-10-08 15:03:43 +00:00
dataflow_const_prop.rs Temporarily re-export assert_matches! to reduce stabilization churn 2026-01-19 18:26:53 +11:00
dead_store_elimination.rs show packed alignment in mir_transform_unaligned_packed_ref 2025-11-07 13:57:37 -07:00
deduce_param_attrs.rs Skip parameter attribute deduction for MIR with spread_arg 2025-10-28 23:07:04 +01:00
deref_separator.rs erase coroutine shim dereftemps 2025-10-06 10:57:27 -07:00
dest_prop.rs Put Analysis back into Results. 2025-10-28 10:26:50 +11:00
dump_mir.rs Disable non-required MIR opts with optimize(none) 2025-01-23 17:40:41 +00:00
early_otherwise_branch.rs Introduce Operand::RuntimeChecks. 2025-12-14 17:25:53 +00:00
elaborate_box_derefs.rs Introduce indexvec macro. 2025-10-22 00:52:52 +00:00
elaborate_drop.rs Rollup merge of #148719 - Nadrieril:poly-drop-glue, r=saethlin 2025-11-21 21:34:23 +01:00
elaborate_drops.rs remove some deref_finder uses 2025-10-10 20:30:19 -07:00
erase_deref_temps.rs remove DerefTemp and CopyFromDeref from runtime mir 2025-10-06 10:57:27 -07:00
errors.rs Rename inline_fluent! to msg! 2026-02-14 13:47:52 +01:00
ffi_unwind_calls.rs Handle inline asm in has_ffi_unwind_calls 2025-11-25 16:01:02 +00:00
function_item_references.rs Introduce Operand::RuntimeChecks. 2025-12-14 17:25:53 +00:00
gvn.rs GVN: Do not unify dereferences if they are references 2026-02-04 21:55:57 +08:00
impossible_predicates.rs clippy fixes and code simplification 2025-11-02 08:16:38 +00:00
inline.rs Temporarily re-export assert_matches! to reduce stabilization churn 2026-01-19 18:26:53 +11:00
instsimplify.rs Port rustc_preserve_ub_checks to attr parser. 2026-02-02 21:14:30 +00:00
jump_threading.rs Auto merge of #142881 - cjgillot:minimap, r=saethlin 2025-12-27 03:12:17 +00:00
known_panics_lint.rs Introduce Operand::RuntimeChecks. 2025-12-14 17:25:53 +00:00
large_enums.rs Remove StatementKind::Deinit. 2025-10-10 12:57:24 +00:00
lib.rs Stabilize assert_matches 2026-02-11 14:13:44 +01:00
lint.rs Replace Rvalue::NullaryOp by a variant in mir::ConstValue. 2025-12-14 17:25:51 +00:00
lint_tail_expr_drop_order.rs Rename inline_fluent! to msg! 2026-02-14 13:47:52 +01:00
liveness.rs Consider captures to be used by closures that unwind 2026-02-04 12:35:34 +00:00
lower_intrinsics.rs replace box_new in Box::new with write_via_move 2026-02-16 08:44:56 +01:00
lower_slice_len.rs mir: Add a new method to statement 2025-06-29 20:13:36 +08:00
match_branches.rs mir-opt: Do not transform non-int type in match_branches 2025-05-26 18:15:54 +08:00
mentioned_items.rs account for safe target features in fndef<->closure and fndef<->fndef coerce-lubs 2025-12-03 14:55:41 +00:00
multiple_return_terminators.rs In rustc_mir_tranform, iterate over index newtypes instead of ints 2025-04-12 11:53:07 +00:00
pass_manager.rs Remove all allows for diagnostic_outside_of_impl and untranslatable_diagnostic throughout the codebase 2026-01-19 17:39:49 +01:00
patch.rs Simplify new_local. 2025-10-19 02:22:18 +00:00
post_analysis_normalize.rs do not emit OpaqueCast projections with -Znext-solver 2025-04-17 12:15:04 +02:00
post_drop_elaboration.rs Make check_live_drops into a MirLint. 2024-09-10 09:11:17 +10:00
prettify.rs Use a closure instead of three chained iterators 2025-04-29 14:58:21 +00:00
promote_consts.rs clean up checks for integer div/rem promotion 2026-01-27 17:18:14 -08:00
ref_prop.rs Auto merge of #145513 - beepster4096:erasedereftemps, r=saethlin,cjgillot 2025-10-12 02:34:20 +00:00
remove_noop_landing_pads.rs Remove StatementKind::Deinit. 2025-10-10 12:57:24 +00:00
remove_place_mention.rs mir-opt: Eliminate dead ref statements 2025-10-02 14:55:50 +08:00
remove_storage_markers.rs mir-opt: Eliminate dead ref statements 2025-10-02 14:55:50 +08:00
remove_uninit_drops.rs Apply effects to otherwise edge in dataflow analysis 2025-07-08 18:15:05 -05:00
remove_unneeded_drops.rs Let RemoveUnneededDrops also remove drop_in_place 2025-08-04 23:54:39 -07:00
remove_zsts.rs Remove StatementKind::Deinit. 2025-10-10 12:57:24 +00:00
required_consts.rs Reformat using the new identifier sorting from rustfmt 2024-09-22 19:11:29 -04:00
sanity_check.rs Move MirPass to rustc_mir_transform. 2024-09-03 16:03:46 +10:00
shim.rs Temporarily re-export assert_matches! to reduce stabilization churn 2026-01-19 18:26:53 +11:00
simplify.rs Remove StatementKind::Deinit. 2025-10-10 12:57:24 +00:00
simplify_branches.rs Introduce Operand::RuntimeChecks. 2025-12-14 17:25:53 +00:00
simplify_comparison_integral.rs Run SimplifyComparisonIntegral with opt-level 2 2026-01-12 18:16:39 +08:00
single_use_consts.rs Inline and replace Statement::replace_nop. 2025-02-18 13:43:43 +11:00
sroa.rs Introduce Operand::RuntimeChecks. 2025-12-14 17:25:53 +00:00
ssa.rs remove DerefTemp and CopyFromDeref from runtime mir 2025-10-06 10:57:27 -07:00
ssa_range_prop.rs Propagates assume 2026-01-08 22:31:15 +08:00
strip_debuginfo.rs mir-opt: Eliminate dead statements even if they are used by debuginfos 2025-10-02 14:58:59 +08:00
trivial_const.rs Accept trivial consts based on trivial consts 2025-10-27 13:36:57 -04:00
unreachable_enum_branching.rs Move MirPatch from rustc_middle to rustc_mir_transform. 2025-02-14 16:15:57 +11:00
unreachable_prop.rs Rename tests/codegen into tests/codegen-llvm 2025-07-22 14:28:48 +02:00
validate.rs Replace Rvalue::NullaryOp by a variant in mir::ConstValue. 2025-12-14 17:25:51 +00:00