Auto merge of #100036 - DrMeepster:box_free_free_box, r=oli-obk

Remove `box_free` lang item

This PR removes the `box_free` lang item, replacing it with `Box`'s `Drop` impl. Box dropping is still slightly magic because the contained value is still dropped by the compiler.
This commit is contained in:
bors 2023-06-17 16:10:57 +00:00
commit a8a29070f0
17 changed files with 91 additions and 146 deletions

View File

@ -546,7 +546,8 @@ impl<T> Box<T> {
impl<T: ?Sized, A> Drop for Box<T, A> { impl<T: ?Sized, A> Drop for Box<T, A> {
fn drop(&mut self) { fn drop(&mut self) {
// drop is currently performed by compiler. // inner value is dropped by compiler
libc::free(self.0.pointer.0 as *mut u8);
} }
} }
@ -563,11 +564,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
libc::malloc(size) libc::malloc(size)
} }
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
libc::free(ptr.pointer.0 as *mut u8);
}
#[lang = "drop"] #[lang = "drop"]
pub trait Drop { pub trait Drop {
fn drop(&mut self); fn drop(&mut self);

View File

@ -490,7 +490,8 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> fo
impl<T: ?Sized, A: Allocator> Drop for Box<T, A> { impl<T: ?Sized, A: Allocator> Drop for Box<T, A> {
fn drop(&mut self) { fn drop(&mut self) {
// drop is currently performed by compiler. // inner value is dropped by compiler
libc::free(self.pointer.0 as *mut u8);
} }
} }
@ -507,11 +508,6 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
libc::malloc(size) libc::malloc(size)
} }
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>, _alloc: ()) {
libc::free(ptr.pointer.0 as *mut u8);
}
#[lang = "drop"] #[lang = "drop"]
pub trait Drop { pub trait Drop {
fn drop(&mut self); fn drop(&mut self);

View File

@ -250,7 +250,6 @@ language_item_table! {
FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None; FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None;
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;

View File

@ -409,8 +409,15 @@ where
self.drop_ladder(fields, succ, unwind).0 self.drop_ladder(fields, succ, unwind).0
} }
/// Drops the T contained in a `Box<T>` if it has not been moved out of
#[instrument(level = "debug", ret)] #[instrument(level = "debug", ret)]
fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock { fn open_drop_for_box_contents(
&mut self,
adt: ty::AdtDef<'tcx>,
substs: SubstsRef<'tcx>,
succ: BasicBlock,
unwind: Unwind,
) -> BasicBlock {
// drop glue is sent straight to codegen // drop glue is sent straight to codegen
// box cannot be directly dereferenced // box cannot be directly dereferenced
let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs); let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs);
@ -425,11 +432,7 @@ where
let interior_path = self.elaborator.deref_subpath(self.path); let interior_path = self.elaborator.deref_subpath(self.path);
let succ = self.box_free_block(adt, substs, self.succ, self.unwind); self.drop_subpath(interior, interior_path, succ, unwind)
let unwind_succ =
self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
self.drop_subpath(interior, interior_path, succ, unwind_succ)
} }
#[instrument(level = "debug", ret)] #[instrument(level = "debug", ret)]
@ -453,7 +456,15 @@ where
self.open_drop_for_adt_contents(adt, substs) self.open_drop_for_adt_contents(adt, substs)
}; };
if adt.has_dtor(self.tcx()) { if adt.is_box() {
// we need to drop the inside of the box before running the destructor
let succ = self.destructor_call_block(contents_drop);
let unwind = contents_drop
.1
.map(|unwind| self.destructor_call_block((unwind, Unwind::InCleanup)));
self.open_drop_for_box_contents(adt, substs, succ, unwind)
} else if adt.has_dtor(self.tcx()) {
self.destructor_call_block(contents_drop) self.destructor_call_block(contents_drop)
} else { } else {
contents_drop.0 contents_drop.0
@ -650,7 +661,13 @@ where
}), }),
is_cleanup: unwind.is_cleanup(), is_cleanup: unwind.is_cleanup(),
}; };
self.elaborator.patch().new_block(result)
let destructor_block = self.elaborator.patch().new_block(result);
let block_start = Location { block: destructor_block, statement_index: 0 };
self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
self.drop_flag_test_block(destructor_block, succ, unwind)
} }
/// Create a loop that drops an array: /// Create a loop that drops an array:
@ -851,13 +868,7 @@ where
self.open_drop_for_tuple(&tys) self.open_drop_for_tuple(&tys)
} }
ty::Tuple(fields) => self.open_drop_for_tuple(fields), ty::Tuple(fields) => self.open_drop_for_tuple(fields),
ty::Adt(def, substs) => { ty::Adt(def, substs) => self.open_drop_for_adt(*def, substs),
if def.is_box() {
self.open_drop_for_box(*def, substs)
} else {
self.open_drop_for_adt(*def, substs)
}
}
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
ty::Array(ety, size) => { ty::Array(ety, size) => {
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env()); let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
@ -905,65 +916,6 @@ where
blk blk
} }
/// Creates a block that frees the backing memory of a `Box` if its drop is required (either
/// statically or by checking its drop flag).
///
/// The contained value will not be dropped.
fn box_free_block(
&mut self,
adt: ty::AdtDef<'tcx>,
substs: SubstsRef<'tcx>,
target: BasicBlock,
unwind: Unwind,
) -> BasicBlock {
let block = self.unelaborated_free_block(adt, substs, target, unwind);
self.drop_flag_test_block(block, target, unwind)
}
/// Creates a block that frees the backing memory of a `Box` (without dropping the contained
/// value).
fn unelaborated_free_block(
&mut self,
adt: ty::AdtDef<'tcx>,
substs: SubstsRef<'tcx>,
target: BasicBlock,
unwind: Unwind,
) -> BasicBlock {
let tcx = self.tcx();
let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span));
let args = adt
.variant(FIRST_VARIANT)
.fields
.iter()
.enumerate()
.map(|(i, f)| {
let field = FieldIdx::new(i);
let field_ty = f.ty(tcx, substs);
Operand::Move(tcx.mk_place_field(self.place, field, field_ty))
})
.collect();
let call = TerminatorKind::Call {
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
args,
destination: unit_temp,
target: Some(target),
unwind: if unwind.is_cleanup() {
UnwindAction::Terminate
} else {
UnwindAction::Continue
},
from_hir_call: false,
fn_span: self.source_info.span,
}; // FIXME(#43234)
let free_block = self.new_block(unwind, call);
let block_start = Location { block: free_block, statement_index: 0 };
self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
free_block
}
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
let block = TerminatorKind::Drop { let block = TerminatorKind::Drop {
place: self.place, place: self.place,

View File

@ -123,12 +123,6 @@
//! pointers to these functions even if they never get called anywhere. This can //! pointers to these functions even if they never get called anywhere. This can
//! be seen as a special case of taking a function reference. //! be seen as a special case of taking a function reference.
//! //!
//! #### Boxes
//! Since `Box` expression have special compiler support, no explicit calls to
//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the
//! compiler will generate them. We have to observe `Rvalue::Box` expressions
//! and Box-typed drop-statements for that purpose.
//!
//! //!
//! Interaction with Cross-Crate Inlining //! Interaction with Cross-Crate Inlining
//! ------------------------------------- //! -------------------------------------

View File

@ -432,7 +432,6 @@ symbols! {
bool, bool,
borrowck_graphviz_format, borrowck_graphviz_format,
borrowck_graphviz_postflow, borrowck_graphviz_postflow,
box_free,
box_new, box_new,
box_patterns, box_patterns,
box_syntax, box_syntax,

View File

@ -4,8 +4,10 @@
#[cfg(not(test))] #[cfg(not(test))]
use core::intrinsics; use core::intrinsics;
#[cfg(all(bootstrap, not(test)))]
use core::intrinsics::{min_align_of_val, size_of_val}; use core::intrinsics::{min_align_of_val, size_of_val};
#[cfg(all(bootstrap, not(test)))]
use core::ptr::Unique; use core::ptr::Unique;
#[cfg(not(test))] #[cfg(not(test))]
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
@ -335,14 +337,15 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
} }
} }
#[cfg_attr(not(test), lang = "box_free")] #[cfg(all(bootstrap, not(test)))]
#[lang = "box_free"]
#[inline] #[inline]
// This signature has to be the same as `Box`, otherwise an ICE will happen. // This signature has to be the same as `Box`, otherwise an ICE will happen.
// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
// well. // well.
// For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`, // For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well. // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) { unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
unsafe { unsafe {
let size = size_of_val(ptr.as_ref()); let size = size_of_val(ptr.as_ref());
let align = min_align_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref());

View File

@ -1211,8 +1211,16 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
#[inline]
fn drop(&mut self) { fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler. // the T in the Box is dropped by the compiler before the destructor is run
let ptr = self.0;
unsafe {
let layout = Layout::for_value_raw(ptr.as_ptr());
self.1.deallocate(From::from(ptr.cast()), layout)
}
} }
} }

View File

@ -270,7 +270,7 @@ use core::slice::from_raw_parts_mut;
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use crate::alloc::handle_alloc_error; use crate::alloc::handle_alloc_error;
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use crate::alloc::{box_free, WriteCloneIntoRaw}; use crate::alloc::WriteCloneIntoRaw;
use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::alloc::{AllocError, Allocator, Global, Layout};
use crate::borrow::{Cow, ToOwned}; use crate::borrow::{Cow, ToOwned};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
@ -1442,23 +1442,21 @@ impl<T: ?Sized> Rc<T> {
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
fn from_box(v: Box<T>) -> Rc<T> { fn from_box(src: Box<T>) -> Rc<T> {
unsafe { unsafe {
let (box_unique, alloc) = Box::into_unique(v); let value_size = size_of_val(&*src);
let bptr = box_unique.as_ptr(); let ptr = Self::allocate_for_ptr(&*src);
let value_size = size_of_val(&*bptr);
let ptr = Self::allocate_for_ptr(bptr);
// Copy value as bytes // Copy value as bytes
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(
bptr as *const T as *const u8, &*src as *const T as *const u8,
&mut (*ptr).value as *mut _ as *mut u8, &mut (*ptr).value as *mut _ as *mut u8,
value_size, value_size,
); );
// Free the allocation without dropping its contents // Free the allocation without dropping its contents
box_free(box_unique, alloc); let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop<T>);
drop(src);
Self::from_ptr(ptr) Self::from_ptr(ptr)
} }

View File

@ -33,7 +33,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use crate::alloc::handle_alloc_error; use crate::alloc::handle_alloc_error;
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use crate::alloc::{box_free, WriteCloneIntoRaw}; use crate::alloc::WriteCloneIntoRaw;
use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::alloc::{AllocError, Allocator, Global, Layout};
use crate::borrow::{Cow, ToOwned}; use crate::borrow::{Cow, ToOwned};
use crate::boxed::Box; use crate::boxed::Box;
@ -1360,23 +1360,21 @@ impl<T: ?Sized> Arc<T> {
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
fn from_box(v: Box<T>) -> Arc<T> { fn from_box(src: Box<T>) -> Arc<T> {
unsafe { unsafe {
let (box_unique, alloc) = Box::into_unique(v); let value_size = size_of_val(&*src);
let bptr = box_unique.as_ptr(); let ptr = Self::allocate_for_ptr(&*src);
let value_size = size_of_val(&*bptr);
let ptr = Self::allocate_for_ptr(bptr);
// Copy value as bytes // Copy value as bytes
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(
bptr as *const T as *const u8, &*src as *const T as *const u8,
&mut (*ptr).data as *mut _ as *mut u8, &mut (*ptr).data as *mut _ as *mut u8,
value_size, value_size,
); );
// Free the allocation without dropping its contents // Free the allocation without dropping its contents
box_free(box_unique, alloc); let src = Box::from_raw(Box::into_raw(src) as *mut mem::ManuallyDrop<T>);
drop(src);
Self::from_ptr(ptr) Self::from_ptr(ptr)
} }

View File

@ -11,8 +11,8 @@ it exists. The marker is the attribute `#[lang = "..."]` and there are
various different values of `...`, i.e. various different 'lang various different values of `...`, i.e. various different 'lang
items'. items'.
For example, `Box` pointers require two lang items, one for allocation For example, `Box` pointers require a lang item for allocation.
and one for deallocation. A freestanding program that uses the `Box` A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`: sugar for dynamic allocations via `malloc` and `free`:
```rust,ignore (libc-is-finicky) ```rust,ignore (libc-is-finicky)
@ -48,9 +48,10 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
p p
} }
#[lang = "box_free"] impl<T> Drop for Box<T> {
unsafe fn box_free<T: ?Sized>(ptr: *mut T) { fn drop(&mut self) {
libc::free(ptr as *mut libc::c_void) libc::free(self.0.0.0 as *mut libc::c_void)
}
} }
#[start] #[start]
@ -84,8 +85,8 @@ Other features provided by lang items include:
`contravariant_lifetime`, etc. `contravariant_lifetime`, etc.
Lang items are loaded lazily by the compiler; e.g. if one never uses Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc` `Box` then there is no need to define a function for `exchange_malloc`.
and `box_free`. `rustc` will emit an error when an item is needed `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on. but not found in the current crate or any that it depends on.
Most lang items are defined by `libcore`, but if you're trying to build Most lang items are defined by `libcore`, but if you're trying to build
@ -250,7 +251,6 @@ the source code.
- Allocations - Allocations
- `owned_box`: `liballoc/boxed.rs` - `owned_box`: `liballoc/boxed.rs`
- `exchange_malloc`: `liballoc/heap.rs` - `exchange_malloc`: `liballoc/heap.rs`
- `box_free`: `liballoc/heap.rs`
- Operands - Operands
- `not`: `libcore/ops/bit.rs` - `not`: `libcore/ops/bit.rs`
- `bitand`: `libcore/ops/bit.rs` - `bitand`: `libcore/ops/bit.rs`

View File

@ -9,7 +9,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
= note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
= note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
note: inside `main` note: inside `main`

View File

@ -9,7 +9,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
= note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
= note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
note: inside closure note: inside closure

View File

@ -20,7 +20,7 @@ LL | fn inner(x: &mut i32, f: fn(&mut i32)) {
= note: BACKTRACE (of the first span): = note: BACKTRACE (of the first span):
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::box_free::<i32, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::boxed::Box<i32> as std::ops::Drop>::drop` at RUSTLIB/alloc/src/boxed.rs:LL:CC
= note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::drop_in_place::<std::boxed::Box<i32>> - shim(Some(std::boxed::Box<i32>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
= note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC = note: inside `std::mem::drop::<std::boxed::Box<i32>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
note: inside closure note: inside closure

View File

@ -370,7 +370,7 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
// all: __stack_chk_fail // all: __stack_chk_fail
// strong-NOT: __stack_chk_fail // strong: __stack_chk_fail
// basic-NOT: __stack_chk_fail // basic-NOT: __stack_chk_fail
// none-NOT: __stack_chk_fail // none-NOT: __stack_chk_fail
// missing-NOT: __stack_chk_fail // missing-NOT: __stack_chk_fail

View File

@ -6,36 +6,41 @@
let mut _0: (); let mut _0: ();
let _2: (); let _2: ();
let mut _3: std::boxed::Box<[i32]>; let mut _3: std::boxed::Box<[i32]>;
let mut _4: (); let mut _4: &mut std::boxed::Box<[i32]>;
let mut _5: (); let mut _5: ();
let mut _6: (); let mut _6: &mut std::boxed::Box<[i32]>;
let mut _7: *const [i32]; let mut _7: ();
let mut _8: &mut std::boxed::Box<[i32]>;
let mut _9: ();
let mut _10: *const [i32];
bb0: { bb0: {
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
_3 = move _1; _3 = move _1;
_7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); _10 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]);
_2 = callee(move (*_7)) -> [return: bb3, unwind: bb4]; _2 = callee(move (*_10)) -> [return: bb3, unwind: bb4];
} }
bb1: { bb1 (cleanup): {
resume;
}
bb2: {
StorageDead(_3); StorageDead(_3);
StorageDead(_2); StorageDead(_2);
_0 = const (); _0 = const ();
return; return;
} }
bb2 (cleanup): {
resume;
}
bb3: { bb3: {
_4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1; _4 = &mut _3;
_5 = <Box<[i32]> as Drop>::drop(move _4) -> [return: bb2, unwind: bb1];
} }
bb4 (cleanup): { bb4 (cleanup): {
_6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate]; _8 = &mut _3;
_9 = <Box<[i32]> as Drop>::drop(move _8) -> [return: bb1, unwind terminate];
} }
} }

View File

@ -13,13 +13,10 @@ struct Unique<T: ?Sized>(NonNull<T>);
pub struct Box<T: ?Sized>(Unique<T>); pub struct Box<T: ?Sized>(Unique<T>);
impl<T: ?Sized> Drop for Box<T> { impl<T: ?Sized> Drop for Box<T> {
fn drop(&mut self) {} #[inline(always)]
} fn drop(&mut self) {
dealloc(self.0.0.0)
#[lang = "box_free"] }
#[inline(always)]
unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
dealloc(ptr.0.0)
} }
#[inline(never)] #[inline(never)]