Commit 455cdcb4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rust-6.7' of https://github.com/Rust-for-Linux/linux

Pull rust updates from Miguel Ojeda:
 "A small one compared to the previous one in terms of features. In
  terms of lines, as usual, the 'alloc' version upgrade accounts for
  most of them.

  Toolchain and infrastructure:

   - Upgrade to Rust 1.73.0

     This time around, due to how the kernel and Rust schedules have
     aligned, there are two upgrades in fact. They contain the fixes for
     a few issues we reported to the Rust project.

     In addition, a few cleanups indicated by the upgraded compiler or
     possible thanks to it. For instance, the compiler now detects
     redundant explicit links.

   - A couple changes to the Rust 'Makefile' so that it can be used with
     toybox tools, allowing Rust to be used in the Android kernel build.

  x86:

   - Enable IBT if enabled in C

  Documentation:

   - Add "The Rust experiment" section to the Rust index page

  MAINTAINERS:

   - Add Maintainer Entry Profile field ('P:').

   - Update our 'W:' field to point to the webpage we have been building
     this year"

* tag 'rust-6.7' of https://github.com/Rust-for-Linux/linux:
  docs: rust: add "The Rust experiment" section
  x86: Enable IBT in Rust if enabled in C
  rust: Use grep -Ev rather than relying on GNU grep
  rust: Use awk instead of recent xargs
  rust: upgrade to Rust 1.73.0
  rust: print: use explicit link in documentation
  rust: task: remove redundant explicit link
  rust: kernel: remove `#[allow(clippy::new_ret_no_self)]`
  MAINTAINERS: add Maintainer Entry Profile field for Rust
  MAINTAINERS: update Rust webpage
  rust: upgrade to Rust 1.72.1
  rust: arc: add explicit `drop()` around `Box::from_raw()`
parents 2b93c2c3 3857af38
...@@ -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.71.1 rustc --version Rust (optional) 1.73.0 rustc --version
bindgen (optional) 0.65.1 bindgen --version bindgen (optional) 0.65.1 bindgen --version
GNU make 3.82 make --version GNU make 3.82 make --version
bash 4.2 bash --version bash 4.2 bash --version
......
...@@ -6,6 +6,25 @@ Rust ...@@ -6,6 +6,25 @@ Rust
Documentation related to Rust within the kernel. To start using Rust Documentation related to Rust within the kernel. To start using Rust
in the kernel, please read the quick-start.rst guide. in the kernel, please read the quick-start.rst guide.
The Rust experiment
-------------------
The Rust support was merged in v6.1 into mainline in order to help in
determining whether Rust as a language was suitable for the kernel, i.e. worth
the tradeoffs.
Currently, the Rust support is primarily intended for kernel developers and
maintainers interested in the Rust support, so that they can start working on
abstractions and drivers, as well as helping the development of infrastructure
and tools.
If you are an end user, please note that there are currently no in-tree
drivers/modules suitable or intended for production use, and that the Rust
support is still in development/experimental, especially for certain kernel
configurations.
.. only:: rustdoc and html .. only:: rustdoc and html
You can also browse `rustdoc documentation <rustdoc/kernel/index.html>`_. You can also browse `rustdoc documentation <rustdoc/kernel/index.html>`_.
......
...@@ -18734,9 +18734,10 @@ R: Andreas Hindborg <a.hindborg@samsung.com> ...@@ -18734,9 +18734,10 @@ R: Andreas Hindborg <a.hindborg@samsung.com>
R: Alice Ryhl <aliceryhl@google.com> R: Alice Ryhl <aliceryhl@google.com>
L: rust-for-linux@vger.kernel.org L: rust-for-linux@vger.kernel.org
S: Supported S: Supported
W: https://github.com/Rust-for-Linux/linux W: https://rust-for-linux.com
B: https://github.com/Rust-for-Linux/linux/issues B: https://github.com/Rust-for-Linux/linux/issues
C: zulip://rust-for-linux.zulipchat.com C: zulip://rust-for-linux.zulipchat.com
P: https://rust-for-linux.com/contributing
T: git https://github.com/Rust-for-Linux/linux.git rust-next T: git https://github.com/Rust-for-Linux/linux.git rust-next
F: Documentation/rust/ F: Documentation/rust/
F: rust/ F: rust/
......
...@@ -81,6 +81,7 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y) ...@@ -81,6 +81,7 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y)
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816
# #
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables) KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables)
KBUILD_RUSTFLAGS += -Zcf-protection=branch -Zno-jump-tables
else else
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
endif endif
......
...@@ -336,13 +336,13 @@ quiet_cmd_bindgen = BINDGEN $@ ...@@ -336,13 +336,13 @@ quiet_cmd_bindgen = BINDGEN $@
$(bindgen_target_cflags) $(bindgen_target_extra) $(bindgen_target_cflags) $(bindgen_target_extra)
$(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \ $(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \
$(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters) $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
$(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \ $(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \
$(src)/bindgen_parameters FORCE $(src)/bindgen_parameters FORCE
$(call if_changed_dep,bindgen) $(call if_changed_dep,bindgen)
$(obj)/uapi/uapi_generated.rs: private bindgen_target_flags = \ $(obj)/uapi/uapi_generated.rs: private bindgen_target_flags = \
$(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters) $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
$(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \ $(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \
$(src)/bindgen_parameters FORCE $(src)/bindgen_parameters FORCE
$(call if_changed_dep,bindgen) $(call if_changed_dep,bindgen)
...@@ -364,9 +364,7 @@ $(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers.c FORCE ...@@ -364,9 +364,7 @@ $(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers.c FORCE
quiet_cmd_exports = EXPORTS $@ quiet_cmd_exports = EXPORTS $@
cmd_exports = \ cmd_exports = \
$(NM) -p --defined-only $< \ $(NM) -p --defined-only $< \
| grep -E ' (T|R|D) ' | cut -d ' ' -f 3 \ | awk '/ (T|R|D) / {printf "EXPORT_SYMBOL_RUST_GPL(%s);\n",$$3}' > $@
| xargs -Isymbol \
echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@
$(obj)/exports_core_generated.h: $(obj)/core.o FORCE $(obj)/exports_core_generated.h: $(obj)/core.o FORCE
$(call if_changed,exports) $(call if_changed,exports)
......
...@@ -6,9 +6,7 @@ ...@@ -6,9 +6,7 @@
#[cfg(not(test))] #[cfg(not(test))]
use core::intrinsics; use core::intrinsics;
use core::intrinsics::{min_align_of_val, size_of_val};
use core::ptr::Unique;
#[cfg(not(test))] #[cfg(not(test))]
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
...@@ -40,7 +38,6 @@ ...@@ -40,7 +38,6 @@
#[rustc_nounwind] #[rustc_nounwind]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
#[cfg(not(bootstrap))]
static __rust_no_alloc_shim_is_unstable: u8; static __rust_no_alloc_shim_is_unstable: u8;
} }
...@@ -98,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { ...@@ -98,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
unsafe { unsafe {
// Make sure we don't accidentally allow omitting the allocator shim in // Make sure we don't accidentally allow omitting the allocator shim in
// stable code until it is actually stabilized. // stable code until it is actually stabilized.
#[cfg(not(bootstrap))]
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
__rust_alloc(layout.size(), layout.align()) __rust_alloc(layout.size(), layout.align())
...@@ -339,22 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { ...@@ -339,22 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
} }
} }
#[cfg_attr(not(test), lang = "box_free")]
#[inline]
// 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
// well.
// 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.
pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
unsafe {
let size = size_of_val(ptr.as_ref());
let align = min_align_of_val(ptr.as_ref());
let layout = Layout::from_size_align_unchecked(size, align);
alloc.deallocate(From::from(ptr.cast()), layout)
}
}
// # Allocation error handler // # Allocation error handler
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
...@@ -414,7 +394,6 @@ pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! { ...@@ -414,7 +394,6 @@ pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
static __rust_alloc_error_handler_should_panic: u8; static __rust_alloc_error_handler_should_panic: u8;
} }
#[allow(unused_unsafe)]
if unsafe { __rust_alloc_error_handler_should_panic != 0 } { if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {size} bytes failed") panic!("memory allocation of {size} bytes failed")
} else { } else {
......
...@@ -159,12 +159,12 @@ ...@@ -159,12 +159,12 @@
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::marker::Tuple; use core::marker::Tuple;
use core::marker::Unsize; use core::marker::Unsize;
use core::mem; use core::mem::{self, SizedTypeProperties};
use core::ops::{ use core::ops::{
CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver, CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,
}; };
use core::pin::Pin; use core::pin::Pin;
use core::ptr::{self, Unique}; use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll}; use core::task::{Context, Poll};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
...@@ -483,8 +483,12 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE ...@@ -483,8 +483,12 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
where where
A: Allocator, A: Allocator,
{ {
let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = if T::IS_ZST {
let ptr = alloc.allocate(layout)?.cast(); NonNull::dangling()
} else {
let layout = Layout::new::<mem::MaybeUninit<T>>();
alloc.allocate(layout)?.cast()
};
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
} }
...@@ -553,8 +557,12 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE ...@@ -553,8 +557,12 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
where where
A: Allocator, A: Allocator,
{ {
let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = if T::IS_ZST {
let ptr = alloc.allocate_zeroed(layout)?.cast(); NonNull::dangling()
} else {
let layout = Layout::new::<mem::MaybeUninit<T>>();
alloc.allocate_zeroed(layout)?.cast()
};
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
} }
...@@ -679,14 +687,16 @@ pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { ...@@ -679,14 +687,16 @@ pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
unsafe { let ptr = if T::IS_ZST || len == 0 {
NonNull::dangling()
} else {
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
Ok(l) => l, Ok(l) => l,
Err(_) => return Err(AllocError), Err(_) => return Err(AllocError),
}; };
let ptr = Global.allocate(layout)?; Global.allocate(layout)?.cast()
Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) };
} unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
} }
/// Constructs a new boxed slice with uninitialized contents, with the memory /// Constructs a new boxed slice with uninitialized contents, with the memory
...@@ -711,14 +721,16 @@ pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, Al ...@@ -711,14 +721,16 @@ pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, Al
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
unsafe { let ptr = if T::IS_ZST || len == 0 {
NonNull::dangling()
} else {
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
Ok(l) => l, Ok(l) => l,
Err(_) => return Err(AllocError), Err(_) => return Err(AllocError),
}; };
let ptr = Global.allocate_zeroed(layout)?; Global.allocate_zeroed(layout)?.cast()
Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) };
} unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
} }
} }
...@@ -1215,8 +1227,18 @@ pub const fn into_pin(boxed: Self) -> Pin<Self> ...@@ -1215,8 +1227,18 @@ pub const fn into_pin(boxed: Self) -> Pin<Self>
#[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());
if layout.size() != 0 {
self.1.deallocate(From::from(ptr.cast()), layout);
}
}
} }
} }
...@@ -2165,7 +2187,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn E ...@@ -2165,7 +2187,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn E
let err: Box<dyn Error> = self; let err: Box<dyn Error> = self;
<dyn Error>::downcast(err).map_err(|s| unsafe { <dyn Error>::downcast(err).map_err(|s| unsafe {
// Reapply the `Send` marker. // Reapply the `Send` marker.
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s) Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
}) })
} }
} }
...@@ -2179,7 +2201,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self> ...@@ -2179,7 +2201,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>
let err: Box<dyn Error> = self; let err: Box<dyn Error> = self;
<dyn Error>::downcast(err).map_err(|s| unsafe { <dyn Error>::downcast(err).map_err(|s| unsafe {
// Reapply the `Send + Sync` marker. // Reapply the `Send + Sync` marker.
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s) Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
}) })
} }
} }
......
...@@ -58,6 +58,11 @@ ...@@ -58,6 +58,11 @@
//! [`Rc`]: rc //! [`Rc`]: rc
//! [`RefCell`]: core::cell //! [`RefCell`]: core::cell
// 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 effect 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(
...@@ -77,11 +82,6 @@ ...@@ -77,11 +82,6 @@
))] ))]
#![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)] #![deny(fuzzy_provenance_casts)]
...@@ -90,6 +90,8 @@ ...@@ -90,6 +90,8 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![allow(explicit_outlives_requirements)] #![allow(explicit_outlives_requirements)]
#![warn(multiple_supertrait_upcastable)] #![warn(multiple_supertrait_upcastable)]
#![cfg_attr(not(bootstrap), allow(internal_features))]
#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
// //
// Library features: // Library features:
// tidy-alphabetical-start // tidy-alphabetical-start
...@@ -139,7 +141,6 @@ ...@@ -139,7 +141,6 @@
#![feature(maybe_uninit_uninit_array_transpose)] #![feature(maybe_uninit_uninit_array_transpose)]
#![feature(pattern)] #![feature(pattern)]
#![feature(pointer_byte_offsets)] #![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)]
......
...@@ -471,16 +471,26 @@ fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { ...@@ -471,16 +471,26 @@ fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
// See current_memory() why this assert is here // See current_memory() why this assert is here
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) }; let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
let ptr = unsafe {
// `Layout::array` cannot overflow here because it would have // If shrinking to 0, deallocate the buffer. We don't reach this point
// overflowed earlier when capacity was larger. // for the T::IS_ZST case since current_memory() will have returned
let new_size = mem::size_of::<T>().unchecked_mul(cap); // None.
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); if cap == 0 {
self.alloc unsafe { self.alloc.deallocate(ptr, layout) };
.shrink(ptr, layout, new_layout) self.ptr = Unique::dangling();
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? self.cap = 0;
}; } else {
self.set_ptr_and_cap(ptr, cap); let ptr = unsafe {
// `Layout::array` cannot overflow here because it would have
// overflowed earlier when capacity was larger.
let new_size = mem::size_of::<T>().unchecked_mul(cap);
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
self.alloc
.shrink(ptr, layout, new_layout)
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
};
self.set_ptr_and_cap(ptr, cap);
}
Ok(()) Ok(())
} }
} }
......
// 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::mem::{ManuallyDrop, SizedTypeProperties};
use core::ptr; use core::ptr;
use core::slice; use core::slice;
...@@ -9,20 +8,21 @@ ...@@ -9,20 +8,21 @@
/// An iterator which uses a closure to determine if an element should be removed. /// An iterator which uses a closure to determine if an element should be removed.
/// ///
/// This struct is created by [`Vec::drain_filter`]. /// This struct is created by [`Vec::extract_if`].
/// See its documentation for more. /// See its documentation for more.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #![feature(drain_filter)] /// #![feature(extract_if)]
/// ///
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0); /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
/// ``` /// ```
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
#[derive(Debug)] #[derive(Debug)]
pub struct DrainFilter< #[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<
'a, 'a,
T, T,
F, F,
...@@ -39,15 +39,9 @@ pub struct DrainFilter< ...@@ -39,15 +39,9 @@ pub struct DrainFilter<
pub(super) old_len: usize, pub(super) old_len: usize,
/// The filter test predicate. /// The filter test predicate.
pub(super) pred: F, pub(super) pred: F,
/// A flag that indicates a panic has occurred in the filter test predicate.
/// This is used as a hint in the drop implementation to prevent consumption
/// of the remainder of the `DrainFilter`. Any unprocessed items will be
/// backshifted in the `vec`, but no further items will be dropped or
/// tested by the filter predicate.
pub(super) panic_flag: bool,
} }
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A> impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
...@@ -57,63 +51,10 @@ impl<T, F, A: Allocator> DrainFilter<'_, T, F, A> ...@@ -57,63 +51,10 @@ 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.
if !T::IS_ZST && 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 = "extract_if", reason = "recently added", issue = "43244")]
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
...@@ -124,9 +65,7 @@ fn next(&mut self) -> Option<T> { ...@@ -124,9 +65,7 @@ fn next(&mut self) -> Option<T> {
while self.idx < self.old_len { while self.idx < self.old_len {
let i = self.idx; let i = self.idx;
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
self.panic_flag = true;
let drained = (self.pred)(&mut v[i]); let drained = (self.pred)(&mut v[i]);
self.panic_flag = false;
// Update the index *after* the predicate is called. If the index // Update the index *after* the predicate is called. If the index
// is updated prior and the predicate panics, the element at this // is updated prior and the predicate panics, the element at this
// index would be leaked. // index would be leaked.
...@@ -150,50 +89,27 @@ fn size_hint(&self) -> (usize, Option<usize>) { ...@@ -150,50 +89,27 @@ fn size_hint(&self) -> (usize, Option<usize>) {
} }
} }
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A> impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
fn drop(&mut self) { fn drop(&mut self) {
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> unsafe {
where if self.idx < self.old_len && self.del > 0 {
F: FnMut(&mut T) -> bool, // This is a pretty messed up state, and there isn't really an
{ // obviously right thing to do. We don't want to keep trying
drain: &'b mut DrainFilter<'a, T, F, A>, // to execute `pred`, so we just backshift all the unprocessed
} // elements and tell the vec that they still exist. The backshift
// is required to prevent a double-drop of the last successfully
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> // drained item prior to a panic in the predicate.
where let ptr = self.vec.as_mut_ptr();
F: FnMut(&mut T) -> bool, let src = ptr.add(self.idx);
{ let dst = src.sub(self.del);
fn drop(&mut self) { let tail_len = self.old_len - self.idx;
unsafe { src.copy_to(dst, tail_len);
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
// This is a pretty messed up state, and there isn't really an
// obviously right thing to do. We don't want to keep trying
// to execute `pred`, so we just backshift all the unprocessed
// elements and tell the vec that they still exist. The backshift
// is required to prevent a double-drop of the last successfully
// drained item prior to a panic in the predicate.
let ptr = self.drain.vec.as_mut_ptr();
let src = ptr.add(self.drain.idx);
let dst = src.sub(self.drain.del);
let tail_len = self.drain.old_len - self.drain.idx;
src.copy_to(dst, tail_len);
}
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
}
} }
} self.vec.set_len(self.old_len - self.del);
let backshift = BackshiftOnDrop { drain: self };
// Attempt to consume any remaining elements if the filter predicate
// has not yet panicked. We'll backshift any remaining elements
// whether we've already panicked or if the consumption here panics.
if !backshift.drain.panic_flag {
backshift.drain.for_each(drop);
} }
} }
} }
This diff is collapsed.
...@@ -77,7 +77,7 @@ fn try_spec_extend(&mut self, mut iterator: IntoIter<T>) -> Result<(), TryReserv ...@@ -77,7 +77,7 @@ fn try_spec_extend(&mut self, mut iterator: IntoIter<T>) -> Result<(), TryReserv
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A> impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
where where
I: Iterator<Item = &'a T>, I: Iterator<Item = &'a T>,
T: Clone, T: Clone,
...@@ -87,7 +87,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A> ...@@ -87,7 +87,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
} }
} }
impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A> impl<'a, T: 'a, I, A: Allocator> TrySpecExtend<&'a T, I> for Vec<T, A>
where where
I: Iterator<Item = &'a T>, I: Iterator<Item = &'a T>,
T: Clone, T: Clone,
...@@ -98,7 +98,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A> ...@@ -98,7 +98,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A>
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A> impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
where where
T: Copy, T: Copy,
{ {
...@@ -108,7 +108,7 @@ fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { ...@@ -108,7 +108,7 @@ fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
} }
} }
impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A> impl<'a, T: 'a, A: Allocator> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
where where
T: Copy, T: Copy,
{ {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
//! [`compiler_builtins`]: https://github.com/rust-lang/compiler-builtins //! [`compiler_builtins`]: https://github.com/rust-lang/compiler-builtins
//! [`compiler-rt`]: https://compiler-rt.llvm.org/ //! [`compiler-rt`]: https://compiler-rt.llvm.org/
#![allow(internal_features)]
#![feature(compiler_builtins)] #![feature(compiler_builtins)]
#![compiler_builtins] #![compiler_builtins]
#![no_builtins] #![no_builtins]
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
//! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
//! //!
//! ```rust //! ```rust
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! # #![allow(clippy::disallowed_names)]
//! use kernel::{prelude::*, sync::Mutex, new_mutex}; //! use kernel::{prelude::*, sync::Mutex, new_mutex};
//! # use core::pin::Pin; //! # use core::pin::Pin;
//! #[pin_data] //! #[pin_data]
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
//! (or just the stack) to actually initialize a `Foo`: //! (or just the stack) to actually initialize a `Foo`:
//! //!
//! ```rust //! ```rust
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! # #![allow(clippy::disallowed_names)]
//! # use kernel::{prelude::*, sync::Mutex, new_mutex}; //! # use kernel::{prelude::*, sync::Mutex, new_mutex};
//! # use core::pin::Pin; //! # use core::pin::Pin;
//! # #[pin_data] //! # #[pin_data]
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
//! To declare an init macro/function you just return an [`impl PinInit<T, E>`]: //! To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
//! //!
//! ```rust //! ```rust
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! # #![allow(clippy::disallowed_names)]
//! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init}; //! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init};
//! #[pin_data] //! #[pin_data]
//! struct DriverData { //! struct DriverData {
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; /// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
...@@ -288,7 +288,7 @@ macro_rules! stack_pin_init { ...@@ -288,7 +288,7 @@ macro_rules! stack_pin_init {
/// # Examples /// # Examples
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
/// # use macros::pin_data; /// # use macros::pin_data;
/// # use core::{alloc::AllocError, pin::Pin}; /// # use core::{alloc::AllocError, pin::Pin};
...@@ -314,7 +314,7 @@ macro_rules! stack_pin_init { ...@@ -314,7 +314,7 @@ macro_rules! stack_pin_init {
/// ``` /// ```
/// ///
/// ```rust,ignore /// ```rust,ignore
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
/// # use macros::pin_data; /// # use macros::pin_data;
/// # use core::{alloc::AllocError, pin::Pin}; /// # use core::{alloc::AllocError, pin::Pin};
...@@ -366,7 +366,7 @@ macro_rules! stack_try_pin_init { ...@@ -366,7 +366,7 @@ macro_rules! stack_try_pin_init {
/// The syntax is almost identical to that of a normal `struct` initializer: /// The syntax is almost identical to that of a normal `struct` initializer:
/// ///
/// ```rust /// ```rust
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// #[pin_data] /// #[pin_data]
...@@ -411,7 +411,7 @@ macro_rules! stack_try_pin_init { ...@@ -411,7 +411,7 @@ macro_rules! stack_try_pin_init {
/// To create an initializer function, simply declare it like this: /// To create an initializer function, simply declare it like this:
/// ///
/// ```rust /// ```rust
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, prelude::*, init::*}; /// # use kernel::{init, pin_init, prelude::*, init::*};
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
...@@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init { ...@@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init {
/// Users of `Foo` can now create it like this: /// Users of `Foo` can now create it like this:
/// ///
/// ```rust /// ```rust
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
...@@ -466,7 +466,7 @@ macro_rules! stack_try_pin_init { ...@@ -466,7 +466,7 @@ macro_rules! stack_try_pin_init {
/// They can also easily embed it into their own `struct`s: /// They can also easily embed it into their own `struct`s:
/// ///
/// ```rust /// ```rust
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # #![allow(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin; /// # use core::pin::Pin;
/// # #[pin_data] /// # #[pin_data]
......
...@@ -399,6 +399,7 @@ macro_rules! pr_debug ( ...@@ -399,6 +399,7 @@ macro_rules! pr_debug (
/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and /// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
/// `alloc::format!` for information about the formatting syntax. /// `alloc::format!` for information about the formatting syntax.
/// ///
/// [`pr_info!`]: crate::pr_info!
/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont /// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html /// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
/// ///
......
...@@ -302,7 +302,7 @@ fn drop(&mut self) { ...@@ -302,7 +302,7 @@ fn drop(&mut self) {
// The count reached zero, we must free the memory. // The count reached zero, we must free the memory.
// //
// SAFETY: The pointer was initialised from the result of `Box::leak`. // SAFETY: The pointer was initialised from the result of `Box::leak`.
unsafe { Box::from_raw(self.ptr.as_ptr()) }; unsafe { drop(Box::from_raw(self.ptr.as_ptr())) };
} }
} }
} }
......
...@@ -91,7 +91,6 @@ unsafe impl Sync for CondVar {} ...@@ -91,7 +91,6 @@ unsafe impl Sync for CondVar {}
impl CondVar { impl CondVar {
/// Constructs a new condvar initialiser. /// Constructs a new condvar initialiser.
#[allow(clippy::new_ret_no_self)]
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> { pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pin_init!(Self { pin_init!(Self {
_pin: PhantomPinned, _pin: PhantomPinned,
......
...@@ -99,7 +99,6 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {} ...@@ -99,7 +99,6 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
impl<T, B: Backend> Lock<T, B> { impl<T, B: Backend> Lock<T, B> {
/// Constructs a new lock initialiser. /// Constructs a new lock initialiser.
#[allow(clippy::new_ret_no_self)]
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> { pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pin_init!(Self { pin_init!(Self {
data: UnsafeCell::new(t), data: UnsafeCell::new(t),
......
...@@ -82,7 +82,7 @@ impl Task { ...@@ -82,7 +82,7 @@ impl Task {
/// Returns a task reference for the currently executing task/thread. /// Returns a task reference for the currently executing task/thread.
/// ///
/// The recommended way to get the current task/thread is to use the /// The recommended way to get the current task/thread is to use the
/// [`current`](crate::current) macro because it is safe. /// [`current`] macro because it is safe.
/// ///
/// # Safety /// # Safety
/// ///
......
...@@ -31,7 +31,7 @@ llvm) ...@@ -31,7 +31,7 @@ llvm)
fi fi
;; ;;
rustc) rustc)
echo 1.71.1 echo 1.73.0
;; ;;
bindgen) bindgen)
echo 0.65.1 echo 0.65.1
......
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