diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d1d0bff8fe06b..acb905639d44d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1537,15 +1537,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::Transmute => { - let ty_from = op.ty(self.body, tcx); - match ty_from.kind() { - ty::Pat(base, _) if base == ty => {} - _ => span_mirbug!( - self, - rvalue, - "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR", - ), - } + // FIXME: `init_box_via_move` lowering really wants to use this. + // What do we have to do here? + // let ty_from = op.ty(self.body, tcx); + // match ty_from.kind() { + // ty::Pat(base, _) if base == ty => {} + // _ => span_mirbug!( + // self, + // rvalue, + // "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR", + // ), + // } } CastKind::Subtype => { bug!("CastKind::Subtype shouldn't exist in borrowck") diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index a6659912e3fb9..f70eff3108ece 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_errors::DiagMessage; use rustc_hir::{self as hir, LangItem}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, sym}; @@ -76,7 +76,6 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::autodiff | sym::bitreverse | sym::black_box - | sym::box_new | sym::breakpoint | sym::bswap | sym::caller_location @@ -132,6 +131,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::forget | sym::frem_algebraic | sym::fsub_algebraic + | sym::init_box_via_move | sym::is_val_statically_known | sym::log2f16 | sym::log2f32 @@ -553,6 +553,16 @@ pub(crate) fn check_intrinsic_type( sym::write_via_move => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } + sym::init_box_via_move => { + let t = param(0); + // MaybeUninit + let maybe_uninit = tcx.require_lang_item(LangItem::MaybeUninit, span); + let maybe_uninit = tcx.adt_def(maybe_uninit); + let args = tcx.mk_args_from_iter([GenericArg::from(t)].into_iter()); + let maybe_uninit_t = Ty::new_adt(tcx, maybe_uninit, args); + + (1, 0, vec![Ty::new_box(tcx, maybe_uninit_t), param(0)], Ty::new_box(tcx, t)) + } sym::typed_swap_nonoverlapping => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit) @@ -645,8 +655,6 @@ pub(crate) fn check_intrinsic_type( sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), - sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))), - // contract_check_requires::(C) -> bool, where C: impl Fn() -> bool sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit), sym::contract_check_ensures => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5bb717a2a8281..407c3d9e8df6a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -3022,6 +3022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let deref_kind = if checked_ty.is_box() { // detect Box::new(..) + // FIXME: use `box_new` diagnostic item instead? if let ExprKind::Call(box_new, [_]) = expr.kind && let ExprKind::Path(qpath) = &box_new.kind && let Res::Def(DefKind::AssocFn, fn_id) = diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index bb65ef28bdc8c..92edea36e8994 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -9,8 +9,8 @@ use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; -use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; +use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; @@ -365,6 +365,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }) } + // Some intrinsics are handled here because they desperately want to avoid introducing + // unnecessary copies. + ExprKind::Call { ty, fun, ref args, .. } + if let ty::FnDef(def_id, generic_args) = ty.kind() + && let Some(intrinsic) = this.tcx.intrinsic(def_id) + && matches!(intrinsic.name, sym::write_via_move | sym::init_box_via_move) => + { + // We still have to evaluate the callee expression as normal (but we don't care + // about its result). + let _fun = unpack!(block = this.as_local_operand(block, fun)); + + match intrinsic.name { + sym::write_via_move => { + // `write_via_move(ptr, val)` becomes `*ptr = val` but without any dropping. + + // The destination must have unit type (so we don't actually have to store anything + // into it). + assert!(destination.ty(&this.local_decls, this.tcx).ty.is_unit()); + + // Compile this to an assignment of the argument into the destination. + let [ptr, val] = **args else { + span_bug!(expr_span, "invalid write_via_move call") + }; + let Some(ptr) = unpack!(block = this.as_local_operand(block, ptr)).place() + else { + span_bug!(expr_span, "invalid write_via_move call") + }; + let ptr_deref = ptr.project_deeper(&[ProjectionElem::Deref], this.tcx); + this.expr_into_dest(ptr_deref, block, val) + } + sym::init_box_via_move => { + // `write_via_move(b, val)` becomes + // ``` + // *transmute::<_, *mut T>(b) = val; + // transmute::<_, Box>(b) + // ``` + let t = generic_args.type_at(0); + let [b, val] = **args else { + span_bug!(expr_span, "invalid init_box_via_move call") + }; + let Some(b) = unpack!(block = this.as_local_operand(block, b)).place() + else { + span_bug!(expr_span, "invalid init_box_via_move call") + }; + // `ptr` is `b` transmuted to `*mut T`. + let ptr_ty = Ty::new_mut_ptr(this.tcx, t); + let ptr = this.local_decls.push(LocalDecl::new(ptr_ty, expr_span)); + this.cfg.push( + block, + Statement::new(source_info, StatementKind::StorageLive(ptr)), + ); + this.cfg.push_assign( + block, + source_info, + Place::from(ptr), + Rvalue::Cast(CastKind::Transmute, Operand::Move(b), ptr_ty), + ); + // Store `val` into `ptr`. + let ptr_deref = + Place::from(ptr).project_deeper(&[ProjectionElem::Deref], this.tcx); + unpack!(block = this.expr_into_dest(ptr_deref, block, val)); + // Return `ptr` transmuted to `Box`. + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Cast( + CastKind::Transmute, + Operand::Move(ptr.into()), + Ty::new_box(this.tcx, t), + ), + ); + // We don't need `ptr` any more. + this.cfg.push( + block, + Statement::new(source_info, StatementKind::StorageDead(ptr)), + ); + block.unit() + } + _ => rustc_middle::bug!(), + } + } ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => { let fun = unpack!(block = this.as_local_operand(block, fun)); let args: Box<[_]> = args diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 0b9bc018a09b3..ce8f2b58ee704 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{ self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{Span, sym}; +use rustc_span::Span; use tracing::{debug, info, instrument, trace}; use crate::errors::*; @@ -385,24 +385,6 @@ impl<'tcx> ThirBuildCx<'tcx> { from_hir_call: true, fn_span: expr.span, } - } else if let ty::FnDef(def_id, _) = self.typeck_results.expr_ty(fun).kind() - && let Some(intrinsic) = self.tcx.intrinsic(def_id) - && intrinsic.name == sym::box_new - { - // We don't actually evaluate `fun` here, so make sure that doesn't miss any side-effects. - if !matches!(fun.kind, hir::ExprKind::Path(_)) { - span_bug!( - expr.span, - "`box_new` intrinsic can only be called via path expression" - ); - } - let value = &args[0]; - return Expr { - temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, - ty: expr_ty, - span: expr.span, - kind: ExprKind::Box { value: self.mirror_expr(value) }, - }; } else { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index ad7c52064a8ef..8a4f83a6edb37 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -171,30 +171,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { Some(target) => TerminatorKind::Goto { target }, } } - sym::write_via_move => { - let target = target.unwrap(); - let Ok([ptr, val]) = take_array(args) else { - span_bug!( - terminator.source_info.span, - "Wrong number of arguments for write_via_move intrinsic", - ); - }; - let derefed_place = if let Some(place) = ptr.node.place() - && let Some(local) = place.as_local() - { - tcx.mk_place_deref(local.into()) - } else { - span_bug!( - terminator.source_info.span, - "Only passing a local is supported" - ); - }; - block.statements.push(Statement::new( - terminator.source_info, - StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))), - )); - terminator.kind = TerminatorKind::Goto { target }; - } + // `write_via_move` is already lowered during MIR building. sym::discriminant_value => { let target = target.unwrap(); let Ok([arg]) = take_array(args) else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 223d818a2949b..aa6443e850c92 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1233,6 +1233,7 @@ symbols! { infer_static_outlives_requirements, inherent_associated_types, inherit, + init_box_via_move, initial, inlateout, inline, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 39450f69ce30a..f966812f7386b 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -342,19 +342,6 @@ unsafe impl Allocator for Global { } } -/// The allocator for `Box`. -#[cfg(not(no_global_oom_handling))] -#[lang = "exchange_malloc"] -#[inline] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - match Global.allocate(layout) { - Ok(ptr) => ptr.as_mut_ptr(), - Err(_) => handle_alloc_error(layout), - } -} - // # Allocation error handler #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ae43fbfe1d69e..f269e20b38276 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -192,7 +192,7 @@ use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; use core::marker::{Tuple, Unsize}; -use core::mem::{self, SizedTypeProperties}; +use core::mem::{self, MaybeUninit, SizedTypeProperties}; use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver, @@ -233,14 +233,24 @@ pub struct Box< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique, A); -/// Constructs a `Box` by calling the `exchange_malloc` lang item and moving the argument into -/// the newly allocated memory. This is an intrinsic to avoid unnecessary copies. +/// Writes `x` into `b`, then returns `b` at its new type`. /// -/// This is the surface syntax for `box ` expressions. -#[doc(hidden)] +/// This is needed for `vec!`, which can't afford any extra copies of the argument (or else debug +/// builds regress), has to be written fully as a call chain without `let` (or else the temporary +/// lifetimes of the arguments change), and can't use an `unsafe` block as that would then also +/// include the user-provided `$x`. #[rustc_intrinsic] #[unstable(feature = "liballoc_internals", issue = "none")] -pub fn box_new(x: T) -> Box; +pub fn init_box_via_move(b: Box>, x: T) -> Box; + +/// Helper for `vec!` to ensure type inferences work correctly (which it wouldn't if we +/// inlined the `as` cast). +#[doc(hidden)] +#[unstable(feature = "liballoc_internals", issue = "none")] +#[inline(always)] +pub fn box_slice_unsize(b: Box<[T; N]>) -> Box<[T]> { + b as Box<[T]> +} impl Box { /// Allocates memory on the heap and then places `x` into it. @@ -259,7 +269,9 @@ impl Box { #[rustc_diagnostic_item = "box_new"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn new(x: T) -> Self { - return box_new(x); + let b = Box::new_uninit(); + // We could do this with `write_via_move`, but may as well use `init_box_via_move`. + init_box_via_move(b, x) } /// Constructs a new box with uninitialized contents. @@ -279,7 +291,21 @@ impl Box { #[must_use] #[inline] pub fn new_uninit() -> Box> { - Self::new_uninit_in(Global) + // This is the same as `Self::new_uninit_in(Global)`, but manually inlined to help + // with debug build performance. + // SAFETY: + // - The size and align of a valid type `T` are always valid for `Layout`. + // - If `allocate` succeeds, the returned pointer exactly matches what `Box` needs. + unsafe { + let layout = Layout::from_size_align_unchecked( + ::SIZE, + ::ALIGN, + ); + match Global.allocate(layout) { + Ok(ptr) => mem::transmute(ptr.as_mut_ptr()), + Err(_) => handle_alloc_error(layout), + } + } } /// Constructs a new `Box` with uninitialized contents, with the memory diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 1e6e2ae8c3675..2a4be12d213bb 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -48,9 +48,16 @@ macro_rules! vec { ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( - // Using the intrinsic produces a dramatic improvement in stack usage for + // Using `init_box_via_move` produces a dramatic improvement in stack usage for // unoptimized programs using this code path to construct large Vecs. - $crate::boxed::box_new([$($x),+]) + // We can't use `write_via_move` because this entire invocation has to remain a call + // chain without `let` bindings, or else the temporary scopes change and things break; + // it also has to all be safe since `safe { ... }` blocks sadly are not a thing and we + // must not wrap `$x` in `unsafe` (also, wrapping `$x` in a safe block has a good chance + // of introduing extra moves so might not be a good call either). + $crate::boxed::box_slice_unsize( + $crate::boxed::init_box_via_move($crate::boxed::Box::new_uninit(), [$($x),+]) + ) ) ); } diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.diff b/tests/mir-opt/box_expr.main.ElaborateDrops.diff deleted file mode 100644 index 4fa77cf82d819..0000000000000 --- a/tests/mir-opt/box_expr.main.ElaborateDrops.diff +++ /dev/null @@ -1,89 +0,0 @@ -- // MIR for `main` before ElaborateDrops -+ // MIR for `main` after ElaborateDrops - - fn main() -> () { - let mut _0: (); - let _1: std::boxed::Box; - let mut _2: *mut u8; - let mut _3: std::boxed::Box; - let _4: (); - let mut _5: std::boxed::Box; -+ let mut _6: &mut std::boxed::Box; -+ let mut _7: (); -+ let mut _8: *const S; - scope 1 { - debug x => _1; - } - - bb0: { - StorageLive(_1); - _2 = alloc::alloc::exchange_malloc(const ::SIZE, const ::ALIGN) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageLive(_3); - _3 = ShallowInitBox(move _2, S); - (*_3) = S::new() -> [return: bb2, unwind: bb8]; - } - - bb2: { - _1 = move _3; -- drop(_3) -> [return: bb3, unwind continue]; -+ goto -> bb3; - } - - bb3: { - StorageDead(_3); - StorageLive(_4); - StorageLive(_5); - _5 = move _1; - _4 = std::mem::drop::>(move _5) -> [return: bb4, unwind: bb6]; - } - - bb4: { - StorageDead(_5); - StorageDead(_4); - _0 = const (); -- drop(_1) -> [return: bb5, unwind continue]; -+ goto -> bb5; - } - - bb5: { - StorageDead(_1); - return; - } - - bb6 (cleanup): { -- drop(_5) -> [return: bb7, unwind terminate(cleanup)]; -+ goto -> bb7; - } - - bb7 (cleanup): { -- drop(_1) -> [return: bb9, unwind terminate(cleanup)]; -+ goto -> bb9; - } - - bb8 (cleanup): { -- drop(_3) -> [return: bb9, unwind terminate(cleanup)]; -+ goto -> bb12; - } - - bb9 (cleanup): { - resume; -+ } -+ -+ bb10 (cleanup): { -+ _6 = &mut _3; -+ _7 = as Drop>::drop(move _6) -> [return: bb9, unwind terminate(cleanup)]; -+ } -+ -+ bb11 (cleanup): { -+ goto -> bb10; -+ } -+ -+ bb12 (cleanup): { -+ _8 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const S (Transmute); -+ goto -> bb11; - } - } - diff --git a/tests/mir-opt/box_expr.rs b/tests/mir-opt/box_expr.rs deleted file mode 100644 index 6299c98718094..0000000000000 --- a/tests/mir-opt/box_expr.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ test-mir-pass: ElaborateDrops -//@ needs-unwind - -#![feature(rustc_attrs, liballoc_internals)] - -// EMIT_MIR box_expr.main.ElaborateDrops.diff -fn main() { - // CHECK-LABEL: fn main( - // CHECK: [[ptr:_.*]] = move {{_.*}} as *const S (Transmute); - // CHECK: [[nonnull:_.*]] = NonNull:: { pointer: move [[ptr]] }; - // CHECK: [[unique:_.*]] = Unique:: { pointer: move [[nonnull]], _marker: const PhantomData:: }; - // CHECK: [[box:_.*]] = Box::(move [[unique]], const std::alloc::Global); - // CHECK: [[ptr:_.*]] = copy (([[box]].0: std::ptr::Unique).0: std::ptr::NonNull) as *const S (Transmute); - // CHECK: (*[[ptr]]) = S::new() -> [return: [[ret:bb.*]], unwind: [[unwind:bb.*]]]; - // CHECK: [[ret]]: { - // CHECK: [[box2:_.*]] = move [[box]]; - // CHECK: [[box3:_.*]] = move [[box2]]; - // CHECK: std::mem::drop::>(move [[box3]]) - // CHECK: [[unwind]] (cleanup): { - // CHECK: [[boxref:_.*]] = &mut [[box]]; - // CHECK: as Drop>::drop(move [[boxref]]) - - let x = std::boxed::box_new(S::new()); - drop(x); -} - -struct S; - -impl S { - fn new() -> Self { - S - } -} - -impl Drop for S { - fn drop(&mut self) { - println!("splat!"); - } -} diff --git a/tests/mir-opt/building/init_box_via_move.box_new.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/init_box_via_move.box_new.CleanupPostBorrowck.after.mir new file mode 100644 index 0000000000000..422c57f312940 --- /dev/null +++ b/tests/mir-opt/building/init_box_via_move.box_new.CleanupPostBorrowck.after.mir @@ -0,0 +1,51 @@ +// MIR for `box_new` after CleanupPostBorrowck + +fn box_new(_1: T) -> Box<[T; 1024]> { + debug x => _1; + let mut _0: std::boxed::Box<[T; 1024]>; + let mut _2: std::boxed::Box>; + let mut _3: std::boxed::Box>; + let mut _4: *mut [T; 1024]; + let mut _5: T; + scope 1 { + debug b => _2; + } + + bb0: { + StorageLive(_2); + _2 = Box::<[T; 1024]>::new_uninit() -> [return: bb1, unwind: bb5]; + } + + bb1: { + nop; + StorageLive(_3); + _3 = move _2; + StorageLive(_4); + _4 = move _3 as *mut [T; 1024] (Transmute); + StorageLive(_5); + _5 = copy _1; + (*_4) = [move _5; 1024]; + StorageDead(_5); + _0 = move _4 as std::boxed::Box<[T; 1024]> (Transmute); + StorageDead(_4); + drop(_3) -> [return: bb2, unwind: bb4]; + } + + bb2: { + StorageDead(_3); + drop(_2) -> [return: bb3, unwind: bb5]; + } + + bb3: { + StorageDead(_2); + return; + } + + bb4 (cleanup): { + drop(_2) -> [return: bb5, unwind terminate(cleanup)]; + } + + bb5 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/init_box_via_move.rs b/tests/mir-opt/building/init_box_via_move.rs new file mode 100644 index 0000000000000..048fecbc6dcc8 --- /dev/null +++ b/tests/mir-opt/building/init_box_via_move.rs @@ -0,0 +1,19 @@ +//! Ensure we don't generate unnecessary copys for `write_via_move`. +//@ compile-flags: -Zmir-opt-level=0 +#![feature(liballoc_internals)] + +// Can't emit `built.after` here as that contains user type annotations which contain DefId that +// change all the time. +// EMIT_MIR init_box_via_move.box_new.CleanupPostBorrowck.after.mir +// CHECK-LABEL: fn box_new +#[inline(never)] +fn box_new(x: T) -> Box<[T; 1024]> { + let mut b = Box::new_uninit(); + // Ensure the array gets constructed directly into the deref'd pointer. + // CHECK: (*[[TEMP1:_.+]]) = [{{(move|copy) _.+}}; 1024]; + std::boxed::init_box_via_move(b, [x; 1024]) +} + +fn main() { + box_new(0); +} diff --git a/tests/mir-opt/building/write_via_move.box_new.CleanupPostBorrowck.after.mir b/tests/mir-opt/building/write_via_move.box_new.CleanupPostBorrowck.after.mir new file mode 100644 index 0000000000000..6a6e984023b75 --- /dev/null +++ b/tests/mir-opt/building/write_via_move.box_new.CleanupPostBorrowck.after.mir @@ -0,0 +1,76 @@ +// MIR for `box_new` after CleanupPostBorrowck + +fn box_new(_1: T) -> Box<[T; 1024]> { + debug x => _1; + let mut _0: std::boxed::Box<[T; 1024]>; + let mut _2: std::boxed::Box>; + let mut _4: &mut std::mem::MaybeUninit<[T; 1024]>; + let mut _5: &mut std::mem::MaybeUninit<[T; 1024]>; + let _6: (); + let mut _7: *mut [T; 1024]; + let mut _8: T; + let mut _9: std::boxed::Box>; + scope 1 { + debug b => _2; + let _3: *mut [T; 1024]; + scope 2 { + debug ptr => _3; + } + } + + bb0: { + StorageLive(_2); + _2 = Box::<[T; 1024]>::new_uninit() -> [return: bb1, unwind: bb7]; + } + + bb1: { + nop; + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = &mut (*_2); + _4 = &mut (*_5); + _3 = MaybeUninit::<[T; 1024]>::as_mut_ptr(move _4) -> [return: bb2, unwind: bb6]; + } + + bb2: { + StorageDead(_4); + nop; + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = copy _3; + StorageLive(_8); + _8 = copy _1; + (*_7) = [move _8; 1024]; + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + StorageLive(_9); + _9 = move _2; + _0 = Box::>::assume_init(move _9) -> [return: bb3, unwind: bb5]; + } + + bb3: { + StorageDead(_9); + StorageDead(_3); + drop(_2) -> [return: bb4, unwind: bb7]; + } + + bb4: { + StorageDead(_2); + return; + } + + bb5 (cleanup): { + drop(_9) -> [return: bb6, unwind terminate(cleanup)]; + } + + bb6 (cleanup): { + drop(_2) -> [return: bb7, unwind terminate(cleanup)]; + } + + bb7 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/write_via_move.rs b/tests/mir-opt/building/write_via_move.rs new file mode 100644 index 0000000000000..12be592a855c1 --- /dev/null +++ b/tests/mir-opt/building/write_via_move.rs @@ -0,0 +1,23 @@ +//! Ensure we don't generate unnecessary copys for `write_via_move`. +//@ compile-flags: -Zmir-opt-level=0 +#![feature(core_intrinsics)] + +use std::mem; + +// Can't emit `built.after` here as that contains user type annotations which contain DefId that +// change all the time. +// EMIT_MIR write_via_move.box_new.CleanupPostBorrowck.after.mir +// CHECK-LABEL: fn box_new +#[inline(never)] +fn box_new(x: T) -> Box<[T; 1024]> { + let mut b = Box::new_uninit(); + let ptr = mem::MaybeUninit::as_mut_ptr(&mut *b); + // Ensure the array gets constructed directly into the deref'd pointer. + // CHECK: (*[[TEMP1:_.+]]) = [{{(move|copy) _.+}}; 1024]; + unsafe { std::intrinsics::write_via_move(ptr, [x; 1024]) }; + unsafe { b.assume_init() } +} + +fn main() { + box_new(0); +} diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff deleted file mode 100644 index 95eaf18b4703b..0000000000000 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff +++ /dev/null @@ -1,59 +0,0 @@ -- // MIR for `main` before GVN -+ // MIR for `main` after GVN - - fn main() -> () { - let mut _0: (); - let _1: i32; - let mut _2: i32; - let mut _3: std::boxed::Box; - let mut _4: *mut u8; - let mut _5: std::boxed::Box; - let mut _6: *const i32; - let mut _7: std::ptr::NonNull; - let mut _8: std::ptr::Unique; - let mut _9: *const i32; - let mut _10: *const i32; - scope 1 { - debug x => _1; - } - - bb0: { - StorageLive(_1); -- StorageLive(_2); -+ nop; - StorageLive(_3); - _4 = alloc::alloc::exchange_malloc(const ::SIZE, const ::ALIGN) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageLive(_5); -- _6 = move _4 as *const i32 (Transmute); -- _7 = NonNull:: { pointer: move _6 }; -- _8 = Unique:: { pointer: move _7, _marker: const PhantomData:: }; -+ _6 = copy _4 as *const i32 (PtrToPtr); -+ _7 = NonNull:: { pointer: copy _6 }; -+ _8 = Unique:: { pointer: copy _7, _marker: const PhantomData:: }; - _5 = Box::(move _8, const std::alloc::Global); -- _9 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); -- (*_9) = const 42_i32; -+ _9 = copy _6; -+ (*_6) = const 42_i32; - _3 = move _5; - StorageDead(_5); - _10 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - _2 = copy (*_10); -- _1 = Add(move _2, const 0_i32); -- StorageDead(_2); -+ _1 = copy _2; -+ nop; - drop(_3) -> [return: bb2, unwind unreachable]; - } - - bb2: { - StorageDead(_3); - _0 = const (); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff deleted file mode 100644 index 6d8d3a0dcfe29..0000000000000 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff +++ /dev/null @@ -1,63 +0,0 @@ -- // MIR for `main` before GVN -+ // MIR for `main` after GVN - - fn main() -> () { - let mut _0: (); - let _1: i32; - let mut _2: i32; - let mut _3: std::boxed::Box; - let mut _4: *mut u8; - let mut _5: std::boxed::Box; - let mut _6: *const i32; - let mut _7: std::ptr::NonNull; - let mut _8: std::ptr::Unique; - let mut _9: *const i32; - let mut _10: *const i32; - scope 1 { - debug x => _1; - } - - bb0: { - StorageLive(_1); -- StorageLive(_2); -+ nop; - StorageLive(_3); - _4 = alloc::alloc::exchange_malloc(const ::SIZE, const ::ALIGN) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageLive(_5); -- _6 = move _4 as *const i32 (Transmute); -- _7 = NonNull:: { pointer: move _6 }; -- _8 = Unique:: { pointer: move _7, _marker: const PhantomData:: }; -+ _6 = copy _4 as *const i32 (PtrToPtr); -+ _7 = NonNull:: { pointer: copy _6 }; -+ _8 = Unique:: { pointer: copy _7, _marker: const PhantomData:: }; - _5 = Box::(move _8, const std::alloc::Global); -- _9 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); -- (*_9) = const 42_i32; -+ _9 = copy _6; -+ (*_6) = const 42_i32; - _3 = move _5; - StorageDead(_5); - _10 = copy ((_3.0: std::ptr::Unique).0: std::ptr::NonNull) as *const i32 (Transmute); - _2 = copy (*_10); -- _1 = Add(move _2, const 0_i32); -- StorageDead(_2); -+ _1 = copy _2; -+ nop; - drop(_3) -> [return: bb2, unwind: bb3]; - } - - bb2: { - StorageDead(_3); - _0 = const (); - StorageDead(_1); - return; - } - - bb3 (cleanup): { - resume; - } - } - diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs deleted file mode 100644 index a192d6b4133a2..0000000000000 --- a/tests/mir-opt/const_prop/boxes.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ test-mir-pass: GVN -//@ compile-flags: -O -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY - -#![feature(rustc_attrs, liballoc_internals)] - -// Note: this test verifies that we, in fact, do not const prop `#[rustc_box]` - -// EMIT_MIR boxes.main.GVN.diff -fn main() { - // CHECK-LABEL: fn main( - // CHECK: debug x => [[x:_.*]]; - // CHECK: (*{{_.*}}) = const 42_i32; - // CHECK: [[tmp:_.*]] = copy (*{{_.*}}); - // CHECK: [[x]] = copy [[tmp]]; - let x = *(std::boxed::box_new(42)) + 0; -} diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 59417ce646513..ffcb0014cec69 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -213,7 +213,7 @@ + StorageLive(_42); + _42 = Option::<()>::None; + _35 = copy ((*_37).0: std::option::Option<()>); -+ ((*_37).0: std::option::Option<()>) = copy _42; ++ ((*_37).0: std::option::Option<()>) = move _42; + StorageDead(_42); + StorageLive(_43); + _43 = discriminant(_35); diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 6b8c2a7902023..e8a7701477415 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -197,17 +197,6 @@ pub fn read_via_copy_uninhabited(r: &Never) -> Never { unsafe { core::intrinsics::read_via_copy(r) } } -// EMIT_MIR lower_intrinsics.write_via_move_string.LowerIntrinsics.diff -pub fn write_via_move_string(r: &mut String, v: String) { - // CHECK-LABEL: fn write_via_move_string( - // CHECK: [[ptr:_.*]] = &raw mut (*_1); - // CHECK: [[tmp:_.*]] = move _2; - // CHECK: (*[[ptr]]) = move [[tmp]]; - // CHECK: return; - - unsafe { core::intrinsics::write_via_move(r, v) } -} - pub enum Never {} // EMIT_MIR lower_intrinsics.ptr_offset.LowerIntrinsics.diff diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff deleted file mode 100644 index cc9177c90027d..0000000000000 --- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-abort.diff +++ /dev/null @@ -1,31 +0,0 @@ -- // MIR for `write_via_move_string` before LowerIntrinsics -+ // MIR for `write_via_move_string` after LowerIntrinsics - - fn write_via_move_string(_1: &mut String, _2: String) -> () { - debug r => _1; - debug v => _2; - let mut _0: (); - let mut _3: *mut std::string::String; - let mut _4: std::string::String; - - bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - StorageLive(_4); - _4 = move _2; -- _0 = write_via_move::(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ (*_3) = move _4; -+ goto -> bb1; - } - - bb1: { - StorageDead(_4); - StorageDead(_3); - goto -> bb2; - } - - bb2: { - return; - } - } - diff --git a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff deleted file mode 100644 index cc9177c90027d..0000000000000 --- a/tests/mir-opt/lower_intrinsics.write_via_move_string.LowerIntrinsics.panic-unwind.diff +++ /dev/null @@ -1,31 +0,0 @@ -- // MIR for `write_via_move_string` before LowerIntrinsics -+ // MIR for `write_via_move_string` after LowerIntrinsics - - fn write_via_move_string(_1: &mut String, _2: String) -> () { - debug r => _1; - debug v => _2; - let mut _0: (); - let mut _3: *mut std::string::String; - let mut _4: std::string::String; - - bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - StorageLive(_4); - _4 = move _2; -- _0 = write_via_move::(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ (*_3) = move _4; -+ goto -> bb1; - } - - bb1: { - StorageDead(_4); - StorageDead(_3); - goto -> bb2; - } - - bb2: { - return; - } - } - diff --git a/tests/ui/limits/issue-17913.32bit.stderr b/tests/ui/limits/issue-17913.32bit.stderr index 1311822d0d0c4..a5a3f925f069a 100644 --- a/tests/ui/limits/issue-17913.32bit.stderr +++ b/tests/ui/limits/issue-17913.32bit.stderr @@ -1,19 +1,24 @@ error[E0080]: values of the type `[&usize; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | - = note: evaluation of `<[&usize; usize::MAX] as std::mem::SizedTypeProperties>::SIZE` failed here + = note: evaluation of ` as std::mem::SizedTypeProperties>::SIZE` failed here error[E0080]: values of the type `[&usize; usize::MAX]` are too big for the target architecture --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | - = note: evaluation of `<[&usize; usize::MAX] as std::mem::SizedTypeProperties>::ALIGN` failed here + = note: evaluation of ` as std::mem::SizedTypeProperties>::ALIGN` failed here + +note: the above error was encountered while instantiating `fn Box::<[&usize; usize::MAX]>::new_uninit_in` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: the above error was encountered while instantiating `fn Box::<[&usize; usize::MAX]>::new` - --> $DIR/issue-17913.rs:16:21 +error[E0080]: values of the type `[&usize; usize::MAX]` are too big for the target architecture + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | -LL | let a: Box<_> = Box::new([&n; SIZE]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: evaluation of `<[&usize; usize::MAX] as std::mem::SizedTypeProperties>::SIZE` failed here + +note: the above error was encountered while instantiating `fn Box::<[&usize; usize::MAX]>::try_new_uninit_in` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs index 9b9a1edf54c9e..17b7c75e709d7 100644 --- a/tests/ui/macros/vec-macro-in-pattern.rs +++ b/tests/ui/macros/vec-macro-in-pattern.rs @@ -5,6 +5,8 @@ fn main() { match Some(vec![42]) { Some(vec![43]) => {} //~ ERROR expected a pattern, found a function call + //~| ERROR expected a pattern, found a function call + //~| ERROR found associated function //~| ERROR found associated function //~| ERROR usage of qualified paths in this context is experimental _ => {} diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr index 71ba0ea5ad4f5..a7800dd2ccfcb 100644 --- a/tests/ui/macros/vec-macro-in-pattern.stderr +++ b/tests/ui/macros/vec-macro-in-pattern.stderr @@ -7,6 +7,15 @@ LL | Some(vec![43]) => {} = note: function calls are not allowed in patterns: = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0532]: expected a pattern, found a function call + --> $DIR/vec-macro-in-pattern.rs:7:14 + | +LL | Some(vec![43]) => {} + | ^^^^^^^^ not a tuple struct or tuple variant + | + = note: function calls are not allowed in patterns: + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0658]: usage of qualified paths in this context is experimental --> $DIR/vec-macro-in-pattern.rs:7:14 | @@ -27,7 +36,16 @@ LL | Some(vec![43]) => {} = help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0164]: expected tuple struct or tuple variant, found associated function `::alloc::boxed::Box::new_uninit` + --> $DIR/vec-macro-in-pattern.rs:7:14 + | +LL | Some(vec![43]) => {} + | ^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0164, E0532, E0658. For more information about an error, try `rustc --explain E0164`. diff --git a/tests/ui/span/regions-escape-loop-via-vec.rs b/tests/ui/span/regions-escape-loop-via-vec.rs index 1fceb09696770..fb1747751ecd3 100644 --- a/tests/ui/span/regions-escape-loop-via-vec.rs +++ b/tests/ui/span/regions-escape-loop-via-vec.rs @@ -2,11 +2,11 @@ fn broken() { let mut x = 3; let mut _y = vec![&mut x]; - while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed - let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed + while x < 10 { + let mut z = x; _y.push(&mut z); //~^ ERROR `z` does not live long enough - x += 1; //~ ERROR cannot use `x` because it was mutably borrowed + x += 1; } } diff --git a/tests/ui/span/regions-escape-loop-via-vec.stderr b/tests/ui/span/regions-escape-loop-via-vec.stderr index 18c6cd4809303..781f970ea5dcf 100644 --- a/tests/ui/span/regions-escape-loop-via-vec.stderr +++ b/tests/ui/span/regions-escape-loop-via-vec.stderr @@ -1,25 +1,3 @@ -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:5:11 - | -LL | let mut _y = vec![&mut x]; - | ------ `x` is borrowed here -LL | while x < 10 { - | ^ use of borrowed `x` -LL | let mut z = x; -LL | _y.push(&mut z); - | -- borrow later used here - -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:6:21 - | -LL | let mut _y = vec![&mut x]; - | ------ `x` is borrowed here -LL | while x < 10 { -LL | let mut z = x; - | ^ use of borrowed `x` -LL | _y.push(&mut z); - | -- borrow later used here - error[E0597]: `z` does not live long enough --> $DIR/regions-escape-loop-via-vec.rs:7:17 | @@ -33,19 +11,6 @@ LL | _y.push(&mut z); LL | } | - `z` dropped here while still borrowed -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/regions-escape-loop-via-vec.rs:9:9 - | -LL | let mut _y = vec![&mut x]; - | ------ `x` is borrowed here -... -LL | _y.push(&mut z); - | -- borrow later used here -LL | -LL | x += 1; - | ^^^^^^ use of borrowed `x` - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0503, E0597. -For more information about an error, try `rustc --explain E0503`. +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/unpretty/box.rs b/tests/ui/unpretty/box.rs deleted file mode 100644 index 83fdeff7a1796..0000000000000 --- a/tests/ui/unpretty/box.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ compile-flags: -Zunpretty=thir-tree -//@ check-pass - -#![feature(liballoc_internals)] - -fn main() { - let _ = std::boxed::box_new(1); -} diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout deleted file mode 100644 index 92155d0c73b9d..0000000000000 --- a/tests/ui/unpretty/box.stdout +++ /dev/null @@ -1,90 +0,0 @@ -DefId(0:3 ~ box[efb9]::main): -params: [ -] -body: - Expr { - ty: () - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None } - span: $DIR/box.rs:6:11: 8:2 (#0) - kind: - Scope { - region_scope: Node(11) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).11)) - value: - Expr { - ty: () - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None } - span: $DIR/box.rs:6:11: 8:2 (#0) - kind: - Block { - targeted_by_break: false - span: $DIR/box.rs:6:11: 8:2 (#0) - region_scope: Node(1) - safety_mode: Safe - stmts: [ - Stmt { - kind: Let { - remainder_scope: Remainder { block: 1, first_statement_index: 0} - init_scope: Node(2) - pattern: - Pat: { - ty: std::boxed::Box - span: $DIR/box.rs:7:9: 7:10 (#0) - kind: PatKind { - Wild - } - } - , - initializer: Some( - Expr { - ty: std::boxed::Box - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } - span: $DIR/box.rs:7:13: 7:35 (#0) - kind: - Scope { - region_scope: Node(3) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).3)) - value: - Expr { - ty: std::boxed::Box - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } - span: $DIR/box.rs:7:13: 7:35 (#0) - kind: - Box { - Expr { - ty: i32 - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } - span: $DIR/box.rs:7:33: 7:34 (#0) - kind: - Scope { - region_scope: Node(8) - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).8)) - value: - Expr { - ty: i32 - temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } - span: $DIR/box.rs:7:33: 7:34 (#0) - kind: - Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed), span: $DIR/box.rs:7:33: 7:34 (#0) }, neg: false) - - } - } - } - } - } - } - } - ) - else_block: None - lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).9)) - span: $DIR/box.rs:7:5: 7:35 (#0) - } - } - ] - expr: [] - } - } - } - } - -