Skip to content

Associate an allocator to boxes #50882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/liballoc/alloc.rs
Original file line number Diff line number Diff line change
@@ -40,10 +40,14 @@ extern "Rust" {
/// This type implements the [`Alloc`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
#[cfg(not(test))]
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)]
pub struct Global;

#[cfg(test)]
pub use std::alloc::Global;

/// Allocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
@@ -116,6 +120,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
__rust_alloc_zeroed(layout.size(), layout.align())
}

#[cfg(not(test))]
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global {
#[inline]
@@ -154,25 +159,23 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
align as *mut u8
} else {
let layout = Layout::from_size_align_unchecked(size, align);
let ptr = alloc(layout);
if !ptr.is_null() {
ptr
} else {
handle_alloc_error(layout)
match Global.alloc(layout) {
Ok(ptr) => ptr.as_ptr(),
Err(_) => handle_alloc_error(layout),
}
}
}

#[cfg_attr(not(test), lang = "box_free")]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
pub(crate) unsafe fn box_free<T: ?Sized, A: Alloc>(ptr: Unique<T>, mut a: A) {
let ptr = ptr.as_ptr();
let size = size_of_val(&*ptr);
let align = min_align_of_val(&*ptr);
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
if size != 0 {
let layout = Layout::from_size_align_unchecked(size, align);
dealloc(ptr as *mut u8, layout);
a.dealloc(NonNull::new_unchecked(ptr).cast(), layout);
}
}

187 changes: 138 additions & 49 deletions src/liballoc/boxed.rs

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions src/liballoc/raw_vec.rs
Original file line number Diff line number Diff line change
@@ -693,19 +693,20 @@ impl<T, A: Alloc> RawVec<T, A> {

}

impl<T> RawVec<T, Global> {
/// Converts the entire buffer into `Box<[T]>`.
impl<T, A: Alloc> RawVec<T, A> {
/// Converts the entire buffer into `Box<[T], A>`.
///
/// While it is not *strictly* Undefined Behavior to call
/// this procedure while some of the RawVec is uninitialized,
/// it certainly makes it trivial to trigger it.
///
/// Note that this will correctly reconstitute any `cap` changes
/// that may have been performed. (see description of type for details)
pub unsafe fn into_box(self) -> Box<[T]> {
pub unsafe fn into_box(self) -> Box<[T], A> {
// NOTE: not calling `cap()` here, actually using the real `cap` field!
let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
let output: Box<[T]> = Box::from_raw(slice);
let a = ptr::read(&self.a);
let output: Box<[T], A> = Box::from_raw_in(slice, a);
mem::forget(self);
output
}
2 changes: 1 addition & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
@@ -690,7 +690,7 @@ impl<T: ?Sized> Rc<T> {
value_size);

// Free the allocation without dropping its contents
box_free(box_unique);
box_free(box_unique, Global);

Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
2 changes: 1 addition & 1 deletion src/liballoc/sync.rs
Original file line number Diff line number Diff line change
@@ -590,7 +590,7 @@ impl<T: ?Sized> Arc<T> {
value_size);

// Free the allocation without dropping its contents
box_free(box_unique);
box_free(box_unique, Global);

Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
10 changes: 5 additions & 5 deletions src/test/mir-opt/validate_2.rs
Original file line number Diff line number Diff line change
@@ -22,14 +22,14 @@ fn main() {
// fn main() -> () {
// ...
// bb1: {
// Validate(Acquire, [_2: std::boxed::Box<[i32; 3]>]);
// Validate(Release, [_2: std::boxed::Box<[i32; 3]>]);
// _1 = move _2 as std::boxed::Box<[i32]> (Unsize);
// Validate(Acquire, [_1: std::boxed::Box<[i32]>]);
// Validate(Acquire, [_2: std::boxed::Box<[i32; 3], std::alloc::Global>]);
// Validate(Release, [_2: std::boxed::Box<[i32; 3], std::alloc::Global>]);
// _1 = move _2 as std::boxed::Box<[i32], std::alloc::Global> (Unsize);
// Validate(Acquire, [_1: std::boxed::Box<[i32], std::alloc::Global>]);
// StorageDead(_2);
// StorageDead(_3);
// _0 = ();
// Validate(Release, [_1: std::boxed::Box<[i32]>]);
// Validate(Release, [_1: std::boxed::Box<[i32], std::alloc::Global>]);
// drop(_1) -> [return: bb2, unwind: bb3];
// }
// ...
4 changes: 2 additions & 2 deletions src/test/ui/e0119/conflict-with-std.stderr
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@ LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `alloc`:
- impl<T> std::convert::AsRef<T> for std::boxed::Box<T>
where T: ?Sized;
- impl<T, A> std::convert::AsRef<T> for std::boxed::Box<T, A>
where A: std::alloc::Alloc, T: ?Sized;

error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
--> $DIR/conflict-with-std.rs:24:1
2 changes: 1 addition & 1 deletion src/test/ui/issue-14092.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,6 @@
// except according to those terms.

fn fn1(0: Box) {}
//~^ ERROR wrong number of type arguments: expected 1, found 0 [E0243]
//~^ ERROR wrong number of type arguments: expected at least 1, found 0 [E0243]

fn main() {}
4 changes: 2 additions & 2 deletions src/test/ui/issue-14092.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0243]: wrong number of type arguments: expected 1, found 0
error[E0243]: wrong number of type arguments: expected at least 1, found 0
--> $DIR/issue-14092.rs:11:11
|
LL | fn fn1(0: Box) {}
| ^^^ expected 1 type argument
| ^^^ expected at least 1 type argument

error: aborting due to previous error

8 changes: 4 additions & 4 deletions src/test/ui/issue-41974.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_>`:
error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_, _>`:
--> $DIR/issue-41974.rs:17:1
|
LL | impl<T> Drop for T where T: A { //~ ERROR E0119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `alloc`:
- impl<T> std::ops::Drop for std::boxed::Box<T>
where T: ?Sized;
= note: downstream crates may implement trait `A` for type `std::boxed::Box<_>`
- impl<T, A> std::ops::Drop for std::boxed::Box<T, A>
where A: std::alloc::Alloc, T: ?Sized;
= note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>`

error[E0120]: the Drop trait may only be implemented on structures
--> $DIR/issue-41974.rs:17:18
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>
extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>
]
= note: number of external vids: 3
= note: where <T as std::iter::Iterator>::Item: '_#2r
@@ -60,7 +60,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>
extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>
]
= note: number of external vids: 3
= note: where <T as std::iter::Iterator>::Item: '_#2r
@@ -92,7 +92,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
'_#2r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>
extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>
]
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#3r
@@ -134,7 +134,7 @@ LL | with_signature(x, |mut y| Box::new(y.next()))
'_#2r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>
extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>
]
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#3r
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ LL | with_signature(x, |y| y)
'_#1r,
T,
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>
extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r), std::alloc::Global>
]
= note: number of external vids: 3
= note: where T: '_#2r