Commit 3ed03f4d authored by Miguel Ojeda's avatar Miguel Ojeda

rust: upgrade to Rust 1.68.2

This is the first upgrade to the Rust toolchain since the initial Rust
merge, from 1.62.0 to 1.68.2 (i.e. the latest).

# Context

The kernel currently supports only a single Rust version [1] (rather
than a minimum) given our usage of some "unstable" Rust features [2]
which do not promise backwards compatibility.

The goal is to reach a point where we can declare a minimum version for
the toolchain. For instance, by waiting for some of the features to be
stabilized. Therefore, the first minimum Rust version that the kernel
will support is "in the future".

# Upgrade policy

Given we will eventually need to reach that minimum version, it would be
ideal to upgrade the compiler from time to time to be as close as
possible to that goal and find any issues sooner. In the extreme, we
could upgrade as soon as a new Rust release is out. Of course, upgrading
so often is in stark contrast to what one normally would need for GCC
and LLVM, especially given the release schedule: 6 weeks for Rust vs.
half a year for LLVM and a year for GCC.

Having said that, there is no particular advantage to updating slowly
either: kernel developers in "stable" distributions are unlikely to be
able to use their distribution-provided Rust toolchain for the kernel
anyway [3]. Instead, by routinely upgrading to the latest instead,
kernel developers using Linux distributions that track the latest Rust
release may be able to use those rather than Rust-provided ones,
especially if their package manager allows to pin / hold back /
downgrade the version for some days during windows where the version may
not match. For instance, Arch, Fedora, Gentoo and openSUSE all provide
and track the latest version of Rust as they get released every 6 weeks.

Then, when the minimum version is reached, we will stop upgrading and
decide how wide the window of support will be. For instance, a year of
Rust versions. We will probably want to start small, and then widen it
over time, just like the kernel did originally for LLVM, see commit
3519c4d6 ("Documentation: add minimum clang/llvm version").

# Unstable features stabilized

This upgrade allows us to remove the following unstable features since
they were stabilized:

  - `feature(explicit_generic_args_with_impl_trait)` (1.63).
  - `feature(core_ffi_c)` (1.64).
  - `feature(generic_associated_types)` (1.65).
  - `feature(const_ptr_offset_from)` (1.65, *).
  - `feature(bench_black_box)` (1.66, *).
  - `feature(pin_macro)` (1.68).

The ones marked with `*` apply only to our old `rust` branch, not
mainline yet, i.e. only for code that we may potentially upstream.

With this patch applied, the only unstable feature allowed to be used
outside the `kernel` crate is `new_uninit`, though other code to be
upstreamed may increase the list.

Please see [2] for details.

# Other required changes

Since 1.63, `rustdoc` triggers the `broken_intra_doc_links` lint for
links pointing to exported (`#[macro_export]`) `macro_rules`. An issue
was opened upstream [4], but it turns out it is intended behavior. For
the moment, just add an explicit reference for each link. Later we can
revisit this if `rustdoc` removes the compatibility measure.

Nevertheless, this was helpful to discover a link that was pointing to
the wrong place unintentionally. Since that one was actually wrong, it
is fixed in a previous commit independently.

Another change was the addition of `cfg(no_rc)` and `cfg(no_sync)` in
upstream [5], thus remove our original changes for that.

Similarly, upstream now tests that it compiles successfully with
`#[cfg(not(no_global_oom_handling))]` [6], which allow us to get rid
of some changes, such as an `#[allow(dead_code)]`.

In addition, remove another `#[allow(dead_code)]` due to new uses
within the standard library.

Finally, add `try_extend_trusted` and move the code in `spec_extend.rs`
since upstream moved it for the infallible version.

# `alloc` upgrade and reviewing

There are a large amount of changes, but the vast majority of them are
due to our `alloc` fork being upgraded at once.

There are two kinds of changes to be aware of: the ones coming from
upstream, which we should follow as closely as possible, and the updates
needed in our added fallible APIs to keep them matching the newer
infallible APIs coming from upstream.

Instead of taking a look at the diff of this patch, an alternative
approach is reviewing a diff of the changes between upstream `alloc` and
the kernel's. This allows to easily inspect the kernel additions only,
especially to check if the fallible methods we already have still match
the infallible ones in the new version coming from upstream.

Another approach is reviewing the changes introduced in the additions in
the kernel fork between the two versions. This is useful to spot
potentially unintended changes to our additions.

To apply these approaches, one may follow steps similar to the following
to generate a pair of patches that show the differences between upstream
Rust and the kernel (for the subset of `alloc` we use) before and after
applying this patch:

    # Get the difference with respect to the old version.
    git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
    git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
        cut -d/ -f3- |
        grep -Fv README.md |
        xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
    git -C linux diff --patch-with-stat --summary -R > old.patch
    git -C linux restore rust/alloc

    # Apply this patch.
    git -C linux am rust-upgrade.patch

    # Get the difference with respect to the new version.
    git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
    git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
        cut -d/ -f3- |
        grep -Fv README.md |
        xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
    git -C linux diff --patch-with-stat --summary -R > new.patch
    git -C linux restore rust/alloc

Now one may check the `new.patch` to take a look at the additions (first
approach) or at the difference between those two patches (second
approach). For the latter, a side-by-side tool is recommended.

Link: https://rust-for-linux.com/rust-version-policy [1]
Link: https://github.com/Rust-for-Linux/linux/issues/2 [2]
Link: https://lore.kernel.org/rust-for-linux/CANiq72mT3bVDKdHgaea-6WiZazd8Mvurqmqegbe5JZxVyLR8Yg@mail.gmail.com/ [3]
Link: https://github.com/rust-lang/rust/issues/106142 [4]
Link: https://github.com/rust-lang/rust/pull/89891 [5]
Link: https://github.com/rust-lang/rust/pull/98652 [6]
Reviewed-by: default avatarBjörn Roy Baron <bjorn3_gh@protonmail.com>
Reviewed-by: default avatarGary Guo <gary@garyguo.net>
Reviewed-By: default avatarMartin Rodriguez Reboredo <yakoyoku@gmail.com>
Tested-by: default avatarAriel Miculas <amiculas@cisco.com>
Tested-by: default avatarDavid Gow <davidgow@google.com>
Tested-by: default avatarBoqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/r/20230418214347.324156-4-ojeda@kernel.org
[ Removed `feature(core_ffi_c)` from `uapi` ]
Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent eed7a146
...@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils. ...@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
====================== =============== ======================================== ====================== =============== ========================================
GNU C 5.1 gcc --version GNU C 5.1 gcc --version
Clang/LLVM (optional) 11.0.0 clang --version Clang/LLVM (optional) 11.0.0 clang --version
Rust (optional) 1.62.0 rustc --version Rust (optional) 1.68.2 rustc --version
bindgen (optional) 0.56.0 bindgen --version bindgen (optional) 0.56.0 bindgen --version
GNU make 3.82 make --version GNU make 3.82 make --version
bash 4.2 bash --version bash 4.2 bash --version
......
...@@ -22,21 +22,24 @@ ...@@ -22,21 +22,24 @@
mod tests; mod tests;
extern "Rust" { extern "Rust" {
// These are the magic symbols to call the global allocator. rustc generates // These are the magic symbols to call the global allocator. rustc generates
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
// (the code expanding that attribute macro generates those functions), or to call // (the code expanding that attribute macro generates those functions), or to call
// the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
// otherwise. // otherwise.
// The rustc fork of LLVM also special-cases these function names to be able to optimize them // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
// like `malloc`, `realloc`, and `free`, respectively. // like `malloc`, `realloc`, and `free`, respectively.
#[rustc_allocator] #[rustc_allocator]
#[rustc_allocator_nounwind] #[rustc_nounwind]
fn __rust_alloc(size: usize, align: usize) -> *mut u8; fn __rust_alloc(size: usize, align: usize) -> *mut u8;
#[rustc_allocator_nounwind] #[rustc_deallocator]
#[rustc_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind] #[rustc_reallocator]
#[rustc_nounwind]
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
#[rustc_allocator_nounwind] #[rustc_allocator_zeroed]
#[rustc_nounwind]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
} }
...@@ -72,11 +75,14 @@ ...@@ -72,11 +75,14 @@
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::alloc::{alloc, dealloc, Layout}; /// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
/// ///
/// unsafe { /// unsafe {
/// let layout = Layout::new::<u16>(); /// let layout = Layout::new::<u16>();
/// let ptr = alloc(layout); /// let ptr = alloc(layout);
/// if ptr.is_null() {
/// handle_alloc_error(layout);
/// }
/// ///
/// *(ptr as *mut u16) = 42; /// *(ptr as *mut u16) = 42;
/// assert_eq!(*(ptr as *mut u16), 42); /// assert_eq!(*(ptr as *mut u16), 42);
...@@ -349,7 +355,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { ...@@ -349,7 +355,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
extern "Rust" { extern "Rust" {
// This is the magic symbol to call the global alloc error handler. rustc generates // This is the magic symbol to call the global alloc error handler. rustc generates
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
// default implementations below (`__rdl_oom`) otherwise. // default implementations below (`__rdl_oom`) otherwise.
fn __rust_alloc_error_handler(size: usize, align: usize) -> !; fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
...@@ -394,25 +400,24 @@ fn rt_error(layout: Layout) -> ! { ...@@ -394,25 +400,24 @@ fn rt_error(layout: Layout) -> ! {
#[allow(unused_attributes)] #[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")] #[unstable(feature = "alloc_internals", issue = "none")]
pub mod __alloc_error_handler { pub mod __alloc_error_handler {
use crate::alloc::Layout; // called via generated `__rust_alloc_error_handler` if there is no
// `#[alloc_error_handler]`.
// called via generated `__rust_alloc_error_handler`
// if there is no `#[alloc_error_handler]`
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! { pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
panic!("memory allocation of {size} bytes failed")
}
// if there is an `#[alloc_error_handler]`
#[rustc_std_internal_symbol]
pub unsafe extern "C-unwind" fn __rg_oom(size: usize, align: usize) -> ! {
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
extern "Rust" { extern "Rust" {
#[lang = "oom"] // This symbol is emitted by rustc next to __rust_alloc_error_handler.
fn oom_impl(layout: Layout) -> !; // Its value depends on the -Zoom={panic,abort} compiler option.
static __rust_alloc_error_handler_should_panic: u8;
}
#[allow(unused_unsafe)]
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {size} bytes failed")
} else {
core::panicking::panic_nounwind_fmt(format_args!(
"memory allocation of {size} bytes failed"
))
} }
unsafe { oom_impl(layout) }
} }
} }
......
This diff is collapsed.
...@@ -141,7 +141,7 @@ fn fmt( ...@@ -141,7 +141,7 @@ fn fmt(
" because the computed capacity exceeded the collection's maximum" " because the computed capacity exceeded the collection's maximum"
} }
TryReserveErrorKind::AllocError { .. } => { TryReserveErrorKind::AllocError { .. } => {
" because the memory allocator returned a error" " because the memory allocator returned an error"
} }
}; };
fmt.write_str(reason) fmt.write_str(reason)
...@@ -154,3 +154,6 @@ trait SpecExtend<I: IntoIterator> { ...@@ -154,3 +154,6 @@ trait SpecExtend<I: IntoIterator> {
/// Extends `self` with the contents of the given iterator. /// Extends `self` with the contents of the given iterator.
fn spec_extend(&mut self, iter: I); fn spec_extend(&mut self, iter: I);
} }
#[stable(feature = "try_reserve", since = "1.57.0")]
impl core::error::Error for TryReserveError {}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
//! This library provides smart pointers and collections for managing //! This library provides smart pointers and collections for managing
//! heap-allocated values. //! heap-allocated values.
//! //!
//! This library, like libcore, normally doesn’t need to be used directly //! This library, like core, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html). //! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically //! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead. //! not depend on `std`, so they’d use this crate instead.
...@@ -58,10 +58,6 @@ ...@@ -58,10 +58,6 @@
//! [`Rc`]: rc //! [`Rc`]: rc
//! [`RefCell`]: core::cell //! [`RefCell`]: core::cell
// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
#![allow(unused_attributes)] #![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")] #![stable(feature = "alloc", since = "1.36.0")]
#![doc( #![doc(
...@@ -75,23 +71,30 @@ ...@@ -75,23 +71,30 @@
any(not(feature = "miri-test-libstd"), test, doctest), any(not(feature = "miri-test-libstd"), test, doctest),
no_global_oom_handling, no_global_oom_handling,
not(no_global_oom_handling), not(no_global_oom_handling),
not(no_rc),
not(no_sync),
target_has_atomic = "ptr" target_has_atomic = "ptr"
))] ))]
#![no_std] #![no_std]
#![needs_allocator] #![needs_allocator]
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
// //
// Lints: // Lints:
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]
#![warn(deprecated_in_future)] #![warn(deprecated_in_future)]
#![warn(missing_debug_implementations)] #![warn(missing_debug_implementations)]
#![warn(missing_docs)] #![warn(missing_docs)]
#![allow(explicit_outlives_requirements)] #![allow(explicit_outlives_requirements)]
// //
// Library features: // Library features:
#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))]
#![feature(alloc_layout_extra)] #![feature(alloc_layout_extra)]
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(array_chunks)] #![feature(array_chunks)]
#![feature(array_into_iter_constructors)]
#![feature(array_methods)] #![feature(array_methods)]
#![feature(array_windows)] #![feature(array_windows)]
#![feature(assert_matches)] #![feature(assert_matches)]
...@@ -99,39 +102,53 @@ ...@@ -99,39 +102,53 @@
#![feature(coerce_unsized)] #![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
#![feature(const_box)] #![feature(const_box)]
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
#![cfg_attr(not(no_borrow), feature(const_cow_is_borrowed))] #![cfg_attr(not(no_borrow), feature(const_cow_is_borrowed))]
#![feature(const_convert)] #![feature(const_convert)]
#![feature(const_size_of_val)] #![feature(const_size_of_val)]
#![feature(const_align_of_val)] #![feature(const_align_of_val)]
#![feature(const_ptr_read)] #![feature(const_ptr_read)]
#![feature(const_maybe_uninit_zeroed)]
#![feature(const_maybe_uninit_write)] #![feature(const_maybe_uninit_write)]
#![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_refs_to_cell)] #![feature(const_refs_to_cell)]
#![feature(core_c_str)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(core_ffi_c)] #![feature(core_panic)]
#![feature(const_eval_select)] #![feature(const_eval_select)]
#![feature(const_pin)] #![feature(const_pin)]
#![feature(const_waker)]
#![feature(cstr_from_bytes_until_nul)] #![feature(cstr_from_bytes_until_nul)]
#![feature(dispatch_from_dyn)] #![feature(dispatch_from_dyn)]
#![feature(error_generic_member_access)]
#![feature(error_in_core)]
#![feature(exact_size_is_empty)] #![feature(exact_size_is_empty)]
#![feature(extend_one)] #![feature(extend_one)]
#![feature(fmt_internals)] #![feature(fmt_internals)]
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(hasher_prefixfree_extras)] #![feature(hasher_prefixfree_extras)]
#![feature(inline_const)]
#![feature(inplace_iteration)] #![feature(inplace_iteration)]
#![cfg_attr(test, feature(is_sorted))]
#![feature(iter_advance_by)] #![feature(iter_advance_by)]
#![feature(iter_next_chunk)]
#![feature(iter_repeat_n)]
#![feature(layout_for_ptr)] #![feature(layout_for_ptr)]
#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_uninit_array_transpose)]
#![cfg_attr(test, feature(new_uninit))] #![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)] #![feature(nonnull_slice_from_raw_parts)]
#![feature(pattern)] #![feature(pattern)]
#![feature(pointer_byte_offsets)]
#![feature(provide_any)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(ptr_metadata)] #![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)] #![feature(ptr_sub_ptr)]
#![feature(receiver_trait)] #![feature(receiver_trait)]
#![feature(saturating_int_impl)]
#![feature(set_ptr_value)] #![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
#![feature(slice_group_by)] #![feature(slice_group_by)]
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(slice_ptr_len)] #![feature(slice_ptr_len)]
...@@ -141,15 +158,17 @@ ...@@ -141,15 +158,17 @@
#![feature(trusted_len)] #![feature(trusted_len)]
#![feature(trusted_random_access)] #![feature(trusted_random_access)]
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
#![feature(tuple_trait)]
#![feature(unchecked_math)] #![feature(unchecked_math)]
#![feature(unicode_internals)] #![feature(unicode_internals)]
#![feature(unsize)] #![feature(unsize)]
#![feature(utf8_chunks)]
#![feature(std_internals)]
// //
// Language features: // Language features:
#![feature(allocator_internals)] #![feature(allocator_internals)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)] #![feature(cfg_sanitize)]
#![feature(const_deref)] #![feature(const_deref)]
#![feature(const_mut_refs)] #![feature(const_mut_refs)]
...@@ -163,19 +182,21 @@ ...@@ -163,19 +182,21 @@
#![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(not(test), feature(generator_trait))]
#![feature(hashmap_internals)] #![feature(hashmap_internals)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(let_else)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(never_type)] #![feature(never_type)]
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
#![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(pointer_is_aligned)]
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(stmt_expr_attributes)]
#![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(test))]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(unsized_fn_params)] #![feature(unsized_fn_params)]
#![feature(c_unwind)] #![feature(c_unwind)]
#![feature(with_negative_coherence)]
#![cfg_attr(test, feature(panic_update_hook))]
// //
// Rustdoc features: // Rustdoc features:
#![feature(doc_cfg)] #![feature(doc_cfg)]
...@@ -192,6 +213,8 @@ ...@@ -192,6 +213,8 @@
extern crate std; extern crate std;
#[cfg(test)] #[cfg(test)]
extern crate test; extern crate test;
#[cfg(test)]
mod testing;
// Module with internal macros used by other modules (needs to be included before other modules). // Module with internal macros used by other modules (needs to be included before other modules).
#[cfg(not(no_macros))] #[cfg(not(no_macros))]
...@@ -218,7 +241,7 @@ mod boxed { ...@@ -218,7 +241,7 @@ mod boxed {
#[cfg(not(no_borrow))] #[cfg(not(no_borrow))]
pub mod borrow; pub mod borrow;
pub mod collections; pub mod collections;
#[cfg(not(no_global_oom_handling))] #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
pub mod ffi; pub mod ffi;
#[cfg(not(no_fmt))] #[cfg(not(no_fmt))]
pub mod fmt; pub mod fmt;
...@@ -229,10 +252,9 @@ mod boxed { ...@@ -229,10 +252,9 @@ mod boxed {
pub mod str; pub mod str;
#[cfg(not(no_string))] #[cfg(not(no_string))]
pub mod string; pub mod string;
#[cfg(not(no_sync))] #[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
#[cfg(target_has_atomic = "ptr")]
pub mod sync; pub mod sync;
#[cfg(all(not(no_global_oom_handling), target_has_atomic = "ptr"))] #[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
pub mod task; pub mod task;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
...@@ -243,3 +265,20 @@ mod boxed { ...@@ -243,3 +265,20 @@ mod boxed {
pub mod __export { pub mod __export {
pub use core::format_args; pub use core::format_args;
} }
#[cfg(test)]
#[allow(dead_code)] // Not used in all configurations
pub(crate) mod test_helpers {
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
/// seed not being the same for every RNG invocation too.
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use std::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
std::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish();
let seed_vec =
hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
rand::SeedableRng::from_seed(seed)
}
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
use core::alloc::LayoutError; use core::alloc::LayoutError;
use core::cmp; use core::cmp;
use core::intrinsics; use core::intrinsics;
use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::ops::Drop; use core::ops::Drop;
use core::ptr::{self, NonNull, Unique}; use core::ptr::{self, NonNull, Unique};
use core::slice; use core::slice;
...@@ -177,7 +177,7 @@ pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> { ...@@ -177,7 +177,7 @@ pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0. // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
if mem::size_of::<T>() == 0 || capacity == 0 { if T::IS_ZST || capacity == 0 {
Self::new_in(alloc) Self::new_in(alloc)
} else { } else {
// We avoid `unwrap_or_else` here because it bloats the amount of // We avoid `unwrap_or_else` here because it bloats the amount of
...@@ -212,7 +212,7 @@ fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { ...@@ -212,7 +212,7 @@ fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> { fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0. // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
if mem::size_of::<T>() == 0 || capacity == 0 { if T::IS_ZST || capacity == 0 {
return Ok(Self::new_in(alloc)); return Ok(Self::new_in(alloc));
} }
...@@ -262,7 +262,7 @@ pub fn ptr(&self) -> *mut T { ...@@ -262,7 +262,7 @@ pub fn ptr(&self) -> *mut T {
/// This will always be `usize::MAX` if `T` is zero-sized. /// This will always be `usize::MAX` if `T` is zero-sized.
#[inline(always)] #[inline(always)]
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
if mem::size_of::<T>() == 0 { usize::MAX } else { self.cap } if T::IS_ZST { usize::MAX } else { self.cap }
} }
/// Returns a shared reference to the allocator backing this `RawVec`. /// Returns a shared reference to the allocator backing this `RawVec`.
...@@ -271,7 +271,7 @@ pub fn allocator(&self) -> &A { ...@@ -271,7 +271,7 @@ pub fn allocator(&self) -> &A {
} }
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> { fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
if mem::size_of::<T>() == 0 || self.cap == 0 { if T::IS_ZST || self.cap == 0 {
None None
} else { } else {
// We have an allocated chunk of memory, so we can bypass runtime // We have an allocated chunk of memory, so we can bypass runtime
...@@ -419,7 +419,7 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes ...@@ -419,7 +419,7 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes
// This is ensured by the calling contexts. // This is ensured by the calling contexts.
debug_assert!(additional > 0); debug_assert!(additional > 0);
if mem::size_of::<T>() == 0 { if T::IS_ZST {
// Since we return a capacity of `usize::MAX` when `elem_size` is // Since we return a capacity of `usize::MAX` when `elem_size` is
// 0, getting to here necessarily means the `RawVec` is overfull. // 0, getting to here necessarily means the `RawVec` is overfull.
return Err(CapacityOverflow.into()); return Err(CapacityOverflow.into());
...@@ -445,7 +445,7 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes ...@@ -445,7 +445,7 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes
// `grow_amortized`, but this method is usually instantiated less often so // `grow_amortized`, but this method is usually instantiated less often so
// it's less critical. // it's less critical.
fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
if mem::size_of::<T>() == 0 { if T::IS_ZST {
// Since we return a capacity of `usize::MAX` when the type size is // Since we return a capacity of `usize::MAX` when the type size is
// 0, getting to here necessarily means the `RawVec` is overfull. // 0, getting to here necessarily means the `RawVec` is overfull.
return Err(CapacityOverflow.into()); return Err(CapacityOverflow.into());
...@@ -460,7 +460,7 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve ...@@ -460,7 +460,7 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve
Ok(()) Ok(())
} }
#[allow(dead_code)] #[cfg(not(no_global_oom_handling))]
fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity"); assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
......
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
use crate::alloc::{Allocator, Global}; use crate::alloc::{Allocator, Global};
use core::fmt; use core::fmt;
use core::iter::{FusedIterator, TrustedLen}; use core::iter::{FusedIterator, TrustedLen};
use core::mem; use core::mem::{self, ManuallyDrop, SizedTypeProperties};
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::slice::{self}; use core::slice::{self};
...@@ -67,6 +67,77 @@ pub fn as_slice(&self) -> &[T] { ...@@ -67,6 +67,77 @@ pub fn as_slice(&self) -> &[T] {
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
unsafe { self.vec.as_ref().allocator() } unsafe { self.vec.as_ref().allocator() }
} }
/// Keep unyielded elements in the source `Vec`.
///
/// # Examples
///
/// ```
/// #![feature(drain_keep_rest)]
///
/// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..);
///
/// assert_eq!(drain.next().unwrap(), 'a');
///
/// // This call keeps 'b' and 'c' in the vec.
/// drain.keep_rest();
///
/// // If we wouldn't call `keep_rest()`,
/// // `vec` would be empty.
/// assert_eq!(vec, ['b', 'c']);
/// ```
#[unstable(feature = "drain_keep_rest", issue = "101122")]
pub fn keep_rest(self) {
// At this moment layout looks like this:
//
// [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
// ^-- start \_________/-- unyielded_len \____/-- self.tail_len
// ^-- unyielded_ptr ^-- tail
//
// Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
// Here we want to
// 1. Move [unyielded] to `start`
// 2. Move [tail] to a new start at `start + len(unyielded)`
// 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
// a. In case of ZST, this is the only thing we want to do
// 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
let mut this = ManuallyDrop::new(self);
unsafe {
let source_vec = this.vec.as_mut();
let start = source_vec.len();
let tail = this.tail_start;
let unyielded_len = this.iter.len();
let unyielded_ptr = this.iter.as_slice().as_ptr();
// ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0;
if needs_move {
let start_ptr = source_vec.as_mut_ptr().add(start);
// memmove back unyielded elements
if unyielded_ptr != start_ptr {
let src = unyielded_ptr;
let dst = start_ptr;
ptr::copy(src, dst, unyielded_len);
}
// memmove back untouched tail
if tail != (start + unyielded_len) {
let src = source_vec.as_ptr().add(tail);
let dst = start_ptr.add(unyielded_len);
ptr::copy(src, dst, this.tail_len);
}
}
source_vec.set_len(start + unyielded_len + this.tail_len);
}
}
} }
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")] #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
...@@ -133,7 +204,7 @@ fn drop(&mut self) { ...@@ -133,7 +204,7 @@ fn drop(&mut self) {
let mut vec = self.vec; let mut vec = self.vec;
if mem::size_of::<T>() == 0 { if T::IS_ZST {
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`. // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
unsafe { unsafe {
...@@ -154,9 +225,9 @@ fn drop(&mut self) { ...@@ -154,9 +225,9 @@ fn drop(&mut self) {
} }
// as_slice() must only be called when iter.len() is > 0 because // as_slice() must only be called when iter.len() is > 0 because
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate // it also gets touched by vec::Splice which may turn it into a dangling pointer
// the iterator's internal pointers. Creating a reference to deallocated memory // which would make it and the vec pointer point to different allocations which would
// is invalid even when it is zero-length // lead to invalid pointer arithmetic below.
let drop_ptr = iter.as_slice().as_ptr(); let drop_ptr = iter.as_slice().as_ptr();
unsafe { unsafe {
......
// SPDX-License-Identifier: Apache-2.0 OR MIT // SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::alloc::{Allocator, Global}; use crate::alloc::{Allocator, Global};
use core::ptr::{self}; use core::mem::{self, ManuallyDrop};
use core::slice::{self}; use core::ptr;
use core::slice;
use super::Vec; use super::Vec;
...@@ -56,6 +57,61 @@ impl<T, F, A: Allocator> DrainFilter<'_, T, F, A> ...@@ -56,6 +57,61 @@ impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
self.vec.allocator() self.vec.allocator()
} }
/// Keep unyielded elements in the source `Vec`.
///
/// # Examples
///
/// ```
/// #![feature(drain_filter)]
/// #![feature(drain_keep_rest)]
///
/// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain_filter(|_| true);
///
/// assert_eq!(drain.next().unwrap(), 'a');
///
/// // This call keeps 'b' and 'c' in the vec.
/// drain.keep_rest();
///
/// // If we wouldn't call `keep_rest()`,
/// // `vec` would be empty.
/// assert_eq!(vec, ['b', 'c']);
/// ```
#[unstable(feature = "drain_keep_rest", issue = "101122")]
pub fn keep_rest(self) {
// At this moment layout looks like this:
//
// _____________________/-- old_len
// / \
// [kept] [yielded] [tail]
// \_______/ ^-- idx
// \-- del
//
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
//
// 1. Move [tail] after [kept]
// 2. Update length of the original vec to `old_len - del`
// a. In case of ZST, this is the only thing we want to do
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
let mut this = ManuallyDrop::new(self);
unsafe {
// ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0;
if needs_move && this.idx < this.old_len && this.del > 0 {
let ptr = this.vec.as_mut_ptr();
let src = ptr.add(this.idx);
let dst = src.sub(this.del);
let tail_len = this.old_len - this.idx;
src.copy_to(dst, tail_len);
}
let new_len = this.old_len - this.del;
this.vec.set_len(new_len);
}
}
} }
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
......
...@@ -3,14 +3,16 @@ ...@@ -3,14 +3,16 @@
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use super::AsVecIntoIter; use super::AsVecIntoIter;
use crate::alloc::{Allocator, Global}; use crate::alloc::{Allocator, Global};
#[cfg(not(no_global_oom_handling))]
use crate::collections::VecDeque;
use crate::raw_vec::RawVec; use crate::raw_vec::RawVec;
use core::array;
use core::fmt; use core::fmt;
use core::intrinsics::arith_offset;
use core::iter::{ use core::iter::{
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use core::ops::Deref; use core::ops::Deref;
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
...@@ -40,7 +42,9 @@ pub struct IntoIter< ...@@ -40,7 +42,9 @@ pub struct IntoIter<
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
pub(super) alloc: ManuallyDrop<A>, pub(super) alloc: ManuallyDrop<A>,
pub(super) ptr: *const T, pub(super) ptr: *const T,
pub(super) end: *const T, pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
// ptr == end is a quick test for the Iterator being empty, that works
// for both ZST and non-ZST.
} }
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")] #[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
...@@ -97,13 +101,16 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] { ...@@ -97,13 +101,16 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] {
} }
/// Drops remaining elements and relinquishes the backing allocation. /// Drops remaining elements and relinquishes the backing allocation.
/// This method guarantees it won't panic before relinquishing
/// the backing allocation.
/// ///
/// This is roughly equivalent to the following, but more efficient /// This is roughly equivalent to the following, but more efficient
/// ///
/// ``` /// ```
/// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter(); /// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
/// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter());
/// (&mut into_iter).for_each(core::mem::drop); /// (&mut into_iter).for_each(core::mem::drop);
/// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); } /// std::mem::forget(into_iter);
/// ``` /// ```
/// ///
/// This method is used by in-place iteration, refer to the vec::in_place_collect /// This method is used by in-place iteration, refer to the vec::in_place_collect
...@@ -120,15 +127,45 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) { ...@@ -120,15 +127,45 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
self.ptr = self.buf.as_ptr(); self.ptr = self.buf.as_ptr();
self.end = self.buf.as_ptr(); self.end = self.buf.as_ptr();
// Dropping the remaining elements can panic, so this needs to be
// done only after updating the other fields.
unsafe { unsafe {
ptr::drop_in_place(remaining); ptr::drop_in_place(remaining);
} }
} }
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
#[allow(dead_code)]
pub(crate) fn forget_remaining_elements(&mut self) { pub(crate) fn forget_remaining_elements(&mut self) {
self.ptr = self.end; // For th ZST case, it is crucial that we mutate `end` here, not `ptr`.
// `ptr` must stay aligned, while `end` may be unaligned.
self.end = self.ptr;
}
#[cfg(not(no_global_oom_handling))]
#[inline]
pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
// Keep our `Drop` impl from dropping the elements and the allocator
let mut this = ManuallyDrop::new(self);
// SAFETY: This allocation originally came from a `Vec`, so it passes
// all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
// so the `sub_ptr`s below cannot wrap, and will produce a well-formed
// range. `end` ≤ `buf + cap`, so the range will be in-bounds.
// Taking `alloc` is ok because nothing else is going to look at it,
// since our `Drop` impl isn't going to run so there's no more code.
unsafe {
let buf = this.buf.as_ptr();
let initialized = if T::IS_ZST {
// All the pointers are the same for ZSTs, so it's fine to
// say that they're all at the beginning of the "allocation".
0..this.len()
} else {
this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf)
};
let cap = this.cap;
let alloc = ManuallyDrop::take(&mut this.alloc);
VecDeque::from_contiguous_raw_parts_in(buf, initialized, cap, alloc)
}
} }
} }
...@@ -150,19 +187,18 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { ...@@ -150,19 +187,18 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
#[inline] #[inline]
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
if self.ptr as *const _ == self.end { if self.ptr == self.end {
None None
} else if mem::size_of::<T>() == 0 { } else if T::IS_ZST {
// purposefully don't use 'ptr.offset' because for // `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
// vectors with 0-size elements this would return the // reducing the `end`.
// same pointer. self.end = self.end.wrapping_byte_sub(1);
self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
let old = self.ptr; let old = self.ptr;
self.ptr = unsafe { self.ptr.offset(1) }; self.ptr = unsafe { self.ptr.add(1) };
Some(unsafe { ptr::read(old) }) Some(unsafe { ptr::read(old) })
} }
...@@ -170,7 +206,7 @@ fn next(&mut self) -> Option<T> { ...@@ -170,7 +206,7 @@ fn next(&mut self) -> Option<T> {
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let exact = if mem::size_of::<T>() == 0 { let exact = if T::IS_ZST {
self.end.addr().wrapping_sub(self.ptr.addr()) self.end.addr().wrapping_sub(self.ptr.addr())
} else { } else {
unsafe { self.end.sub_ptr(self.ptr) } unsafe { self.end.sub_ptr(self.ptr) }
...@@ -182,11 +218,9 @@ fn size_hint(&self) -> (usize, Option<usize>) { ...@@ -182,11 +218,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
fn advance_by(&mut self, n: usize) -> Result<(), usize> { fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let step_size = self.len().min(n); let step_size = self.len().min(n);
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
if mem::size_of::<T>() == 0 { if T::IS_ZST {
// SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound // See `next` for why we sub `end` here.
// effectively results in unsigned pointers representing positions 0..usize::MAX, self.end = self.end.wrapping_byte_sub(step_size);
// which is valid for ZSTs.
self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T }
} else { } else {
// SAFETY: the min() above ensures that step_size is in bounds // SAFETY: the min() above ensures that step_size is in bounds
self.ptr = unsafe { self.ptr.add(step_size) }; self.ptr = unsafe { self.ptr.add(step_size) };
...@@ -206,6 +240,43 @@ fn count(self) -> usize { ...@@ -206,6 +240,43 @@ fn count(self) -> usize {
self.len() self.len()
} }
#[inline]
fn next_chunk<const N: usize>(&mut self) -> Result<[T; N], core::array::IntoIter<T, N>> {
let mut raw_ary = MaybeUninit::uninit_array();
let len = self.len();
if T::IS_ZST {
if len < N {
self.forget_remaining_elements();
// Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct
return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
}
self.end = self.end.wrapping_byte_sub(N);
// Safety: ditto
return Ok(unsafe { raw_ary.transpose().assume_init() });
}
if len < N {
// Safety: `len` indicates that this many elements are available and we just checked that
// it fits into the array.
unsafe {
ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len);
self.forget_remaining_elements();
return Err(array::IntoIter::new_unchecked(raw_ary, 0..len));
}
}
// Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
// the array.
return unsafe {
ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
self.ptr = self.ptr.add(N);
Ok(raw_ary.transpose().assume_init())
};
}
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
where where
Self: TrustedRandomAccessNoCoerce, Self: TrustedRandomAccessNoCoerce,
...@@ -219,7 +290,7 @@ unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item ...@@ -219,7 +290,7 @@ unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
// that `T: Copy` so reading elements from the buffer doesn't invalidate // that `T: Copy` so reading elements from the buffer doesn't invalidate
// them for `Drop`. // them for `Drop`.
unsafe { unsafe {
if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
} }
} }
} }
...@@ -230,14 +301,14 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { ...@@ -230,14 +301,14 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
if self.end == self.ptr { if self.end == self.ptr {
None None
} else if mem::size_of::<T>() == 0 { } else if T::IS_ZST {
// See above for why 'ptr.offset' isn't used // See above for why 'ptr.offset' isn't used
self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; self.end = self.end.wrapping_byte_sub(1);
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
self.end = unsafe { self.end.offset(-1) }; self.end = unsafe { self.end.sub(1) };
Some(unsafe { ptr::read(self.end) }) Some(unsafe { ptr::read(self.end) })
} }
...@@ -246,14 +317,12 @@ fn next_back(&mut self) -> Option<T> { ...@@ -246,14 +317,12 @@ fn next_back(&mut self) -> Option<T> {
#[inline] #[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let step_size = self.len().min(n); let step_size = self.len().min(n);
if mem::size_of::<T>() == 0 { if T::IS_ZST {
// SAFETY: same as for advance_by() // SAFETY: same as for advance_by()
self.end = unsafe { self.end = self.end.wrapping_byte_sub(step_size);
arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T
}
} else { } else {
// SAFETY: same as for advance_by() // SAFETY: same as for advance_by()
self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; self.end = unsafe { self.end.sub(step_size) };
} }
let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size);
// SAFETY: same as for advance_by() // SAFETY: same as for advance_by()
......
// SPDX-License-Identifier: Apache-2.0 OR MIT // SPDX-License-Identifier: Apache-2.0 OR MIT
use core::num::{Saturating, Wrapping};
use crate::boxed::Box; use crate::boxed::Box;
#[rustc_specialization_trait] #[rustc_specialization_trait]
pub(super) unsafe trait IsZero { pub(super) unsafe trait IsZero {
/// Whether this value's representation is all zeros /// Whether this value's representation is all zeros,
/// or can be represented with all zeroes.
fn is_zero(&self) -> bool; fn is_zero(&self) -> bool;
} }
...@@ -19,12 +22,14 @@ fn is_zero(&self) -> bool { ...@@ -19,12 +22,14 @@ fn is_zero(&self) -> bool {
}; };
} }
impl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8.
impl_is_zero!(i16, |x| x == 0); impl_is_zero!(i16, |x| x == 0);
impl_is_zero!(i32, |x| x == 0); impl_is_zero!(i32, |x| x == 0);
impl_is_zero!(i64, |x| x == 0); impl_is_zero!(i64, |x| x == 0);
impl_is_zero!(i128, |x| x == 0); impl_is_zero!(i128, |x| x == 0);
impl_is_zero!(isize, |x| x == 0); impl_is_zero!(isize, |x| x == 0);
impl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8.
impl_is_zero!(u16, |x| x == 0); impl_is_zero!(u16, |x| x == 0);
impl_is_zero!(u32, |x| x == 0); impl_is_zero!(u32, |x| x == 0);
impl_is_zero!(u64, |x| x == 0); impl_is_zero!(u64, |x| x == 0);
...@@ -55,16 +60,42 @@ fn is_zero(&self) -> bool { ...@@ -55,16 +60,42 @@ fn is_zero(&self) -> bool {
#[inline] #[inline]
fn is_zero(&self) -> bool { fn is_zero(&self) -> bool {
// Because this is generated as a runtime check, it's not obvious that // Because this is generated as a runtime check, it's not obvious that
// it's worth doing if the array is really long. The threshold here // it's worth doing if the array is really long. The threshold here
// is largely arbitrary, but was picked because as of 2022-05-01 LLVM // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
// can const-fold the check in `vec![[0; 32]; n]` but not in // fails to const-fold the check in `vec![[1; 32]; n]`
// `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
// Feel free to tweak if you have better evidence. // Feel free to tweak if you have better evidence.
N <= 32 && self.iter().all(IsZero::is_zero) N <= 16 && self.iter().all(IsZero::is_zero)
}
}
// This is recursive macro.
macro_rules! impl_for_tuples {
// Stopper
() => {
// No use for implementing for empty tuple because it is ZST.
};
($first_arg:ident $(,$rest:ident)*) => {
unsafe impl <$first_arg: IsZero, $($rest: IsZero,)*> IsZero for ($first_arg, $($rest,)*){
#[inline]
fn is_zero(&self) -> bool{
// Destructure tuple to N references
// Rust allows to hide generic params by local variable names.
#[allow(non_snake_case)]
let ($first_arg, $($rest,)*) = self;
$first_arg.is_zero()
$( && $rest.is_zero() )*
}
}
impl_for_tuples!($($rest),*);
} }
} }
impl_for_tuples!(A, B, C, D, E, F, G, H);
// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null. // `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
// For fat pointers, the bytes that would be the pointer metadata in the `Some` // For fat pointers, the bytes that would be the pointer metadata in the `Some`
// variant are padding in the `None` variant, so ignoring them and // variant are padding in the `None` variant, so ignoring them and
...@@ -118,3 +149,56 @@ fn is_zero(&self) -> bool { ...@@ -118,3 +149,56 @@ fn is_zero(&self) -> bool {
NonZeroUsize, NonZeroUsize,
NonZeroIsize, NonZeroIsize,
); );
macro_rules! impl_is_zero_option_of_num {
($($t:ty,)+) => {$(
unsafe impl IsZero for Option<$t> {
#[inline]
fn is_zero(&self) -> bool {
const {
let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
assert!(none.is_none());
}
self.is_none()
}
}
)+};
}
impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
unsafe impl<T: IsZero> IsZero for Wrapping<T> {
#[inline]
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
unsafe impl<T: IsZero> IsZero for Saturating<T> {
#[inline]
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
macro_rules! impl_for_optional_bool {
($($t:ty,)+) => {$(
unsafe impl IsZero for $t {
#[inline]
fn is_zero(&self) -> bool {
// SAFETY: This is *not* a stable layout guarantee, but
// inside `core` we're allowed to rely on the current rustc
// behaviour that options of bools will be one byte with
// no padding, so long as they're nested less than 254 deep.
let raw: u8 = unsafe { core::mem::transmute(*self) };
raw == 0
}
}
)+};
}
impl_for_optional_bool! {
Option<bool>,
Option<Option<bool>>,
Option<Option<Option<bool>>>,
// Could go further, but not worth the metadata overhead
}
This diff is collapsed.
...@@ -20,6 +20,11 @@ pub(super) fn new(len: &'a mut usize) -> Self { ...@@ -20,6 +20,11 @@ pub(super) fn new(len: &'a mut usize) -> Self {
pub(super) fn increment_len(&mut self, increment: usize) { pub(super) fn increment_len(&mut self, increment: usize) {
self.local_len += increment; self.local_len += increment;
} }
#[inline]
pub(super) fn current_len(&self) -> usize {
self.local_len
}
} }
impl Drop for SetLenOnDrop<'_> { impl Drop for SetLenOnDrop<'_> {
......
// SPDX-License-Identifier: Apache-2.0 OR MIT // SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::alloc::Allocator; use crate::alloc::Allocator;
use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::collections::TryReserveError;
use core::iter::TrustedLen; use core::iter::TrustedLen;
use core::ptr::{self};
use core::slice::{self}; use core::slice::{self};
use super::{IntoIter, SetLenOnDrop, Vec}; use super::{IntoIter, Vec};
// Specialization trait used for Vec::extend // Specialization trait used for Vec::extend
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
...@@ -44,36 +43,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A> ...@@ -44,36 +43,7 @@ impl<T, I, A: Allocator> SpecExtend<T, I> for Vec<T, A>
I: TrustedLen<Item = T>, I: TrustedLen<Item = T>,
{ {
default fn spec_extend(&mut self, iterator: I) { default fn spec_extend(&mut self, iterator: I) {
// This is the case for a TrustedLen iterator. self.extend_trusted(iterator)
let (low, high) = iterator.size_hint();
if let Some(additional) = high {
debug_assert_eq!(
low,
additional,
"TrustedLen iterator's size hint is not exact: {:?}",
(low, high)
);
self.reserve(additional);
unsafe {
let mut ptr = self.as_mut_ptr().add(self.len());
let mut local_len = SetLenOnDrop::new(&mut self.len);
iterator.for_each(move |element| {
ptr::write(ptr, element);
ptr = ptr.offset(1);
// Since the loop executes user code which can panic we have to bump the pointer
// after each step.
// NB can't overflow since we would have had to alloc the address space
local_len.increment_len(1);
});
}
} else {
// Per TrustedLen contract a `None` upper bound means that the iterator length
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
// This avoids additional codegen for a fallback code path which would eventually
// panic anyway.
panic!("capacity overflow");
}
} }
} }
...@@ -82,32 +52,7 @@ impl<T, I, A: Allocator> TrySpecExtend<T, I> for Vec<T, A> ...@@ -82,32 +52,7 @@ impl<T, I, A: Allocator> TrySpecExtend<T, I> for Vec<T, A>
I: TrustedLen<Item = T>, I: TrustedLen<Item = T>,
{ {
default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> { default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> {
// This is the case for a TrustedLen iterator. self.try_extend_trusted(iterator)
let (low, high) = iterator.size_hint();
if let Some(additional) = high {
debug_assert_eq!(
low,
additional,
"TrustedLen iterator's size hint is not exact: {:?}",
(low, high)
);
self.try_reserve(additional)?;
unsafe {
let mut ptr = self.as_mut_ptr().add(self.len());
let mut local_len = SetLenOnDrop::new(&mut self.len);
iterator.for_each(move |element| {
ptr::write(ptr, element);
ptr = ptr.offset(1);
// Since the loop executes user code which can panic we have to bump the pointer
// after each step.
// NB can't overflow since we would have had to alloc the address space
local_len.increment_len(1);
});
}
Ok(())
} else {
Err(TryReserveErrorKind::CapacityOverflow.into())
}
} }
} }
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
//! using this crate. //! using this crate.
#![no_std] #![no_std]
#![feature(core_ffi_c)]
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>. // See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
#![cfg_attr(test, allow(deref_nullptr))] #![cfg_attr(test, allow(deref_nullptr))]
#![cfg_attr(test, allow(unaligned_references))] #![cfg_attr(test, allow(unaligned_references))]
......
...@@ -67,6 +67,8 @@ macro_rules! build_error { ...@@ -67,6 +67,8 @@ macro_rules! build_error {
/// assert!(n > 1); // Run-time check /// assert!(n > 1); // Run-time check
/// } /// }
/// ``` /// ```
///
/// [`static_assert!`]: crate::static_assert!
#[macro_export] #[macro_export]
macro_rules! build_assert { macro_rules! build_assert {
($cond:expr $(,)?) => {{ ($cond:expr $(,)?) => {{
......
...@@ -197,6 +197,7 @@ ...@@ -197,6 +197,7 @@
//! [`Opaque`]: kernel::types::Opaque //! [`Opaque`]: kernel::types::Opaque
//! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init //! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init
//! [`pin_data`]: ::macros::pin_data //! [`pin_data`]: ::macros::pin_data
//! [`pin_init!`]: crate::pin_init!
use crate::{ use crate::{
error::{self, Error}, error::{self, Error},
...@@ -255,6 +256,8 @@ ...@@ -255,6 +256,8 @@
/// A normal `let` binding with optional type annotation. The expression is expected to implement /// A normal `let` binding with optional type annotation. The expression is expected to implement
/// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error /// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error
/// type, then use [`stack_try_pin_init!`]. /// type, then use [`stack_try_pin_init!`].
///
/// [`stack_try_pin_init!`]: crate::stack_try_pin_init!
#[macro_export] #[macro_export]
macro_rules! stack_pin_init { macro_rules! stack_pin_init {
(let $var:ident $(: $t:ty)? = $val:expr) => { (let $var:ident $(: $t:ty)? = $val:expr) => {
...@@ -804,6 +807,8 @@ macro_rules! try_pin_init { ...@@ -804,6 +807,8 @@ macro_rules! try_pin_init {
/// ///
/// This initializer is for initializing data in-place that might later be moved. If you want to /// This initializer is for initializing data in-place that might later be moved. If you want to
/// pin-initialize, use [`pin_init!`]. /// pin-initialize, use [`pin_init!`].
///
/// [`try_init!`]: crate::try_init!
// For a detailed example of how this macro works, see the module documentation of the hidden // For a detailed example of how this macro works, see the module documentation of the hidden
// module `__internal` inside of `init/__internal.rs`. // module `__internal` inside of `init/__internal.rs`.
#[macro_export] #[macro_export]
......
...@@ -14,12 +14,8 @@ ...@@ -14,12 +14,8 @@
#![no_std] #![no_std]
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(coerce_unsized)] #![feature(coerce_unsized)]
#![feature(core_ffi_c)]
#![feature(dispatch_from_dyn)] #![feature(dispatch_from_dyn)]
#![feature(explicit_generic_args_with_impl_trait)]
#![feature(generic_associated_types)]
#![feature(new_uninit)] #![feature(new_uninit)]
#![feature(pin_macro)]
#![feature(receiver_trait)] #![feature(receiver_trait)]
#![feature(unsize)] #![feature(unsize)]
......
...@@ -137,6 +137,8 @@ ...@@ -137,6 +137,8 @@
/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html /// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html /// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html /// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
/// [`pr_info`]: crate::pr_info!
/// [`pr_debug`]: crate::pr_debug!
#[macro_export] #[macro_export]
macro_rules! dbg { macro_rules! dbg {
// NOTE: We cannot use `concat!` to make a static string as a format argument // NOTE: We cannot use `concat!` to make a static string as a format argument
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
//! userspace APIs. //! userspace APIs.
#![no_std] #![no_std]
#![feature(core_ffi_c)]
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>. // See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
#![cfg_attr(test, allow(deref_nullptr))] #![cfg_attr(test, allow(deref_nullptr))]
#![cfg_attr(test, allow(unaligned_references))] #![cfg_attr(test, allow(unaligned_references))]
......
...@@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE ...@@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE
# Compile Rust sources (.rs) # Compile Rust sources (.rs)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
rust_allowed_features := core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro rust_allowed_features := new_uninit
rust_common_cmd = \ rust_common_cmd = \
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
......
...@@ -27,7 +27,7 @@ llvm) ...@@ -27,7 +27,7 @@ llvm)
fi fi
;; ;;
rustc) rustc)
echo 1.62.0 echo 1.68.2
;; ;;
bindgen) bindgen)
echo 0.56.0 echo 0.56.0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment