Skip to content
12 changes: 9 additions & 3 deletions compiler/rustc_serialize/src/serialize.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Support code for encoding and decoding types.

use std::alloc::Allocator;
use std::alloc::{Allocator, Fatal};
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;
Expand Down Expand Up @@ -273,7 +273,10 @@ impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
}
}

impl<D: Decoder, A: Allocator + Default, T: Decodable<D>> Decodable<D> for Box<[T], A> {
impl<D: Decoder, A: Default, T: Decodable<D>> Decodable<D> for Box<[T], A>
where
A: Allocator<ErrorHandling = Fatal>,
{
fn decode(d: &mut D) -> Box<[T], A> {
let v: Vec<T, A> = Decodable::decode(d);
v.into_boxed_slice()
Expand Down Expand Up @@ -308,7 +311,10 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
}
}

impl<D: Decoder, T: Decodable<D>, A: Allocator + Default> Decodable<D> for Vec<T, A> {
impl<D: Decoder, T: Decodable<D>, A: Default> Decodable<D> for Vec<T, A>
where
A: Allocator<ErrorHandling = Fatal>,
{
default fn decode(d: &mut D) -> Vec<T, A> {
let len = d.read_usize();
let allocator = A::default();
Expand Down
220 changes: 220 additions & 0 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,11 @@ unsafe impl Allocator for Global {
},
}
}

#[cfg(not(no_global_oom_handling))]
type ErrorHandling = Fatal;
#[cfg(no_global_oom_handling)]
type ErrorHandling = Fallible;
}

/// The allocator for unique pointers.
Expand Down Expand Up @@ -443,3 +448,218 @@ impl<T: Copy> WriteCloneIntoRaw for T {
unsafe { target.copy_from_nonoverlapping(self, 1) };
}
}

#[cfg(all(not(no_global_oom_handling), not(test)))]
use core::error::Error;

/// Trait for handling alloc errors for allocators which
/// panic or abort instead of returning errors.
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[rustc_specialization_trait]
pub trait HandleAllocError: Error {
/// Globally handle this allocation error
fn handle_alloc_error(self) -> !;
}

/// Error handling mode to use when the user of the type wants to ignore
/// allocation failures, treating them as a fatal error. Functions
/// performing allocation will return values directly.
#[derive(Debug)]
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
pub struct Fatal;

#[unstable(feature = "alloc_internals", issue = "none")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
impl error_handling_sealed::Sealed for Fatal {}

#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
impl ErrorHandling for Fatal {
type Result<T, E: Error> = T;

fn map_result<T, E: Error>(result: Result<T, E>) -> Self::Result<T, E> {
/// Hack around lack of `cfg(no_global_oom_handling)` in core.
///
/// Using post-monomorphization errors and specialization,
/// we can enforce that any error used with `Fatal` implements
/// `HandleAllocError`, without requiring that all errors used
/// with fallible allocation implement it. This also allows
/// for `HandleAllocError` to live with the rest of the
/// global allocation handling in the `alloc` crate.
trait HandleAllocErrorInternal {
fn handle_alloc_error_internal(self) -> !;
}
impl<E: Error> HandleAllocErrorInternal for E {
default fn handle_alloc_error_internal(self) -> ! {
const {
panic!(
"user must implement `HandleAllocError` for any error type used with the `Fatal` kind of `ErrorHandling`"
)
}
}
}
impl<E: HandleAllocError> HandleAllocErrorInternal for E {
fn handle_alloc_error_internal(self) -> ! {
self.handle_alloc_error()
}
}

result.unwrap_or_else(|e| e.handle_alloc_error_internal())
}
}

/// Wrapper around an existing allocator allowing one to
/// use a fallible allocator as an infallible one.
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[derive(Debug)]
pub struct FatalAdapter<A: Allocator<ErrorHandling = Fallible>>(pub A);

#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
unsafe impl<A: Allocator<ErrorHandling = Fallible>> Allocator for FatalAdapter<A> {
fn allocate(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
self.0.allocate(layout)
}

fn allocate_zeroed(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
self.0.allocate_zeroed(layout)
}

unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.deallocate(ptr, layout) }
}

unsafe fn grow(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.grow(ptr, old_layout, new_layout) }
}

unsafe fn grow_zeroed(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
}

unsafe fn shrink(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.shrink(ptr, old_layout, new_layout) }
}

fn by_ref(&self) -> &Self
where
Self: Sized,
{
self
}

type ErrorHandling = Fatal;
}

/// Wrapper around an existing allocator allowing one to
/// use an infallible allocator as a fallible one.
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[derive(Debug)]
pub struct FallibleAdapter<A: Allocator<ErrorHandling = Fatal>>(pub A);

#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
unsafe impl<A: Allocator<ErrorHandling = Fatal>> Allocator for FallibleAdapter<A> {
fn allocate(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
self.0.allocate(layout)
}

fn allocate_zeroed(&self, layout: Layout) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
self.0.allocate_zeroed(layout)
}

unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: Layout) {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.deallocate(ptr, layout) }
}

unsafe fn grow(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.grow(ptr, old_layout, new_layout) }
}

unsafe fn grow_zeroed(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
}

unsafe fn shrink(
&self,
ptr: core::ptr::NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<core::ptr::NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller
unsafe { self.0.shrink(ptr, old_layout, new_layout) }
}

fn by_ref(&self) -> &Self
where
Self: Sized,
{
self
}

type ErrorHandling = Fallible;
}

#[cfg(test)]
pub use std::alloc::{FallibleAdapter, Fatal, FatalAdapter, HandleAllocError};

#[cfg(not(no_global_oom_handling))]
use crate::collections::{TryReserveError, TryReserveErrorKind};

// One central function responsible for reporting capacity overflows. This'll
// ensure that the code generation related to these panics is minimal as there's
// only one location which panics rather than a bunch throughout the module.
#[cfg(not(no_global_oom_handling))]
pub(crate) fn capacity_overflow() -> ! {
panic!("capacity overflow");
}

#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
impl HandleAllocError for TryReserveError {
fn handle_alloc_error(self) -> ! {
match self.kind() {
TryReserveErrorKind::CapacityOverflow => capacity_overflow(),
TryReserveErrorKind::AllocError { layout, .. } => handle_alloc_error(layout),
}
}
}

pub(crate) type AllocResult<A, T, E> =
<<A as Allocator>::ErrorHandling as ErrorHandling>::Result<T, E>;
Loading