Commit a031fe8d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull rust updates from Miguel Ojeda:
 "In terms of lines, most changes this time are on the pinned-init API
  and infrastructure. While we have a Rust version upgrade, and thus a
  bunch of changes from the vendored 'alloc' crate as usual, this time
  those do not account for many lines.

  Toolchain and infrastructure:

   - Upgrade to Rust 1.71.1. This is the second such upgrade, which is a
     smaller jump compared to the last time.

     This version allows us to remove the '__rust_*' allocator functions
     -- the compiler now generates them as expected, thus now our
     'KernelAllocator' is used.

     It also introduces the 'offset_of!' macro in the standard library
     (as an unstable feature) which we will need soon. So far, we were
     using a declarative macro as a prerequisite in some not-yet-landed
     patch series, which did not support sub-fields (i.e. nested
     structs):

         #[repr(C)]
         struct S {
             a: u16,
             b: (u8, u8),
         }

         assert_eq!(offset_of!(S, b.1), 3);

   - Upgrade to bindgen 0.65.1. This is the first time we upgrade its
     version.

     Given it is a fairly big jump, it comes with a fair number of
     improvements/changes that affect us, such as a fix needed to
     support LLVM 16 as well as proper support for '__noreturn' C
     functions, which are now mapped to return the '!' type in Rust:

         void __noreturn f(void); // C
         pub fn f() -> !;         // Rust

   - 'scripts/rust_is_available.sh' improvements and fixes.

     This series takes care of all the issues known so far and adds a
     few new checks to cover for even more cases, plus adds some more
     help texts. All this together will hopefully make problematic
     setups easier to identify and to be solved by users building the
     kernel.

     In addition, it adds a test suite which covers all branches of the
     shell script, as well as tests for the issues found so far.

   - Support rust-analyzer for out-of-tree modules too.

   - Give 'cfg's to rust-analyzer for the 'core' and 'alloc' crates.

   - Drop 'scripts/is_rust_module.sh' since it is not needed anymore.

  Macros crate:

   - New 'paste!' proc macro.

     This macro is a more flexible version of 'concat_idents!': it
     allows the resulting identifier to be used to declare new items and
     it allows to transform the identifiers before concatenating them,
     e.g.

         let x_1 = 42;
         paste!(let [<x _2>] = [<x _1>];);
         assert!(x_1 == x_2);

     The macro is then used for several of the pinned-init API changes
     in this pull.

  Pinned-init API:

   - Make '#[pin_data]' compatible with conditional compilation of
     fields, allowing to write code like:

         #[pin_data]
         pub struct Foo {
             #[cfg(CONFIG_BAR)]
             a: Bar,
             #[cfg(not(CONFIG_BAR))]
             a: Baz,
         }

   - New '#[derive(Zeroable)]' proc macro for the 'Zeroable' trait,
     which allows 'unsafe' implementations for structs where every field
     implements the 'Zeroable' trait, e.g.:

         #[derive(Zeroable)]
         pub struct DriverData {
             id: i64,
             buf_ptr: *mut u8,
             len: usize,
         }

   - Add '..Zeroable::zeroed()' syntax to the 'pin_init!' macro for
     zeroing all other fields, e.g.:

         pin_init!(Buf {
             buf: [1; 64],
             ..Zeroable::zeroed()
         });

   - New '{,pin_}init_array_from_fn()' functions to create array
     initializers given a generator function, e.g.:

         let b: Box<[usize; 1_000]> = Box::init::<Error>(
             init_array_from_fn(|i| i)
         ).unwrap();

         assert_eq!(b.len(), 1_000);
         assert_eq!(b[123], 123);

   - New '{,pin_}chain' methods for '{,Pin}Init<T, E>' that allow to
     execute a closure on the value directly after initialization, e.g.:

         let foo = init!(Foo {
             buf <- init::zeroed()
         }).chain(|foo| {
             foo.setup();
             Ok(())
         });

   - Support arbitrary paths in init macros, instead of just identifiers
     and generic types.

   - Implement the 'Zeroable' trait for the 'UnsafeCell<T>' and
     'Opaque<T>' types.

   - Make initializer values inaccessible after initialization.

   - Make guards in the init macros hygienic.

  'allocator' module:

   - Use 'krealloc_aligned()' in 'KernelAllocator::alloc' preventing
     misaligned allocations when the Rust 1.71.1 upgrade is applied
     later in this pull.

     The equivalent fix for the previous compiler version (where
     'KernelAllocator' is not yet used) was merged into 6.5 already,
     which added the 'krealloc_aligned()' function used here.

   - Implement 'KernelAllocator::{realloc, alloc_zeroed}' for
     performance, using 'krealloc_aligned()' too, which forwards the
     call to the C API.

  'types' module:

   - Make 'Opaque' be '!Unpin', removing the need to add a
     'PhantomPinned' field to Rust structs that contain C structs which
     must not be moved.

   - Make 'Opaque' use 'UnsafeCell' as the outer type, rather than
     inner.

  Documentation:

   - Suggest obtaining the source code of the Rust's 'core' library
     using the tarball instead of the repository.

  MAINTAINERS:

   - Andreas and Alice, from Samsung and Google respectively, are
     joining as reviewers of the "RUST" entry.

  As well as a few other minor changes and cleanups"

* tag 'rust-6.6' of https://github.com/Rust-for-Linux/linux: (42 commits)
  rust: init: update expanded macro explanation
  rust: init: add `{pin_}chain` functions to `{Pin}Init<T, E>`
  rust: init: make `PinInit<T, E>` a supertrait of `Init<T, E>`
  rust: init: implement `Zeroable` for `UnsafeCell<T>` and `Opaque<T>`
  rust: init: add support for arbitrary paths in init macros
  rust: init: add functions to create array initializers
  rust: init: add `..Zeroable::zeroed()` syntax for zeroing all missing fields
  rust: init: make initializer values inaccessible after initializing
  rust: init: wrap type checking struct initializers in a closure
  rust: init: make guards in the init macros hygienic
  rust: add derive macro for `Zeroable`
  rust: init: make `#[pin_data]` compatible with conditional compilation of fields
  rust: init: consolidate init macros
  docs: rust: clarify what 'rustup override' does
  docs: rust: update instructions for obtaining 'core' source
  docs: rust: add command line to rust-analyzer section
  scripts: generate_rust_analyzer: provide `cfg`s for `core` and `alloc`
  rust: bindgen: upgrade to 0.65.1
  rust: enable `no_mangle_with_rust_abi` Clippy lint
  rust: upgrade to Rust 1.71.1
  ...
parents f2586d92 4af84c6a
...@@ -31,8 +31,8 @@ you probably needn't concern yourself with pcmciautils. ...@@ -31,8 +31,8 @@ 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.68.2 rustc --version Rust (optional) 1.71.1 rustc --version
bindgen (optional) 0.56.0 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
binutils 2.25 ld -v binutils 2.25 ld -v
......
...@@ -38,7 +38,9 @@ and run:: ...@@ -38,7 +38,9 @@ and run::
rustup override set $(scripts/min-tool-version.sh rustc) rustup override set $(scripts/min-tool-version.sh rustc)
Otherwise, fetch a standalone installer from: This will configure your working directory to use the correct version of
``rustc`` without affecting your default toolchain. If you are not using
``rustup``, fetch a standalone installer from:
https://forge.rust-lang.org/infra/other-installation-methods.html#standalone https://forge.rust-lang.org/infra/other-installation-methods.html#standalone
...@@ -56,16 +58,17 @@ If ``rustup`` is being used, run:: ...@@ -56,16 +58,17 @@ If ``rustup`` is being used, run::
The components are installed per toolchain, thus upgrading the Rust compiler The components are installed per toolchain, thus upgrading the Rust compiler
version later on requires re-adding the component. version later on requires re-adding the component.
Otherwise, if a standalone installer is used, the Rust repository may be cloned Otherwise, if a standalone installer is used, the Rust source tree may be
into the installation folder of the toolchain:: downloaded into the toolchain's installation folder::
git clone --recurse-submodules \ curl -L "https://static.rust-lang.org/dist/rust-src-$(scripts/min-tool-version.sh rustc).tar.gz" |
--branch $(scripts/min-tool-version.sh rustc) \ tar -xzf - -C "$(rustc --print sysroot)/lib" \
https://github.com/rust-lang/rust \ "rust-src-$(scripts/min-tool-version.sh rustc)/rust-src/lib/" \
$(rustc --print sysroot)/lib/rustlib/src/rust --strip-components=3
In this case, upgrading the Rust compiler version later on requires manually In this case, upgrading the Rust compiler version later on requires manually
updating this clone. updating the source tree (this can be done by removing ``$(rustc --print
sysroot)/lib/rustlib/src/rust`` then rerunning the above command).
libclang libclang
...@@ -98,7 +101,24 @@ the ``bindgen`` tool. A particular version is required. ...@@ -98,7 +101,24 @@ the ``bindgen`` tool. A particular version is required.
Install it via (note that this will download and build the tool from source):: Install it via (note that this will download and build the tool from source)::
cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen-cli
``bindgen`` needs to find a suitable ``libclang`` in order to work. If it is
not found (or a different ``libclang`` than the one found should be used),
the process can be tweaked using the environment variables understood by
``clang-sys`` (the Rust bindings crate that ``bindgen`` uses to access
``libclang``):
* ``LLVM_CONFIG_PATH`` can be pointed to an ``llvm-config`` executable.
* Or ``LIBCLANG_PATH`` can be pointed to a ``libclang`` shared library
or to the directory containing it.
* Or ``CLANG_PATH`` can be pointed to a ``clang`` executable.
For details, please see ``clang-sys``'s documentation at:
https://github.com/KyleMayes/clang-sys#environment-variables
Requirements: Developing Requirements: Developing
...@@ -179,7 +199,9 @@ be used with many editors to enable syntax highlighting, completion, go to ...@@ -179,7 +199,9 @@ be used with many editors to enable syntax highlighting, completion, go to
definition, and other features. definition, and other features.
``rust-analyzer`` needs a configuration file, ``rust-project.json``, which ``rust-analyzer`` needs a configuration file, ``rust-project.json``, which
can be generated by the ``rust-analyzer`` Make target. can be generated by the ``rust-analyzer`` Make target::
make LLVM=1 rust-analyzer
Configuration Configuration
......
...@@ -18577,6 +18577,8 @@ R: Boqun Feng <boqun.feng@gmail.com> ...@@ -18577,6 +18577,8 @@ R: Boqun Feng <boqun.feng@gmail.com>
R: Gary Guo <gary@garyguo.net> R: Gary Guo <gary@garyguo.net>
R: Björn Roy Baron <bjorn3_gh@protonmail.com> R: Björn Roy Baron <bjorn3_gh@protonmail.com>
R: Benno Lossin <benno.lossin@proton.me> R: Benno Lossin <benno.lossin@proton.me>
R: Andreas Hindborg <a.hindborg@samsung.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://github.com/Rust-for-Linux/linux
......
...@@ -467,6 +467,7 @@ export rust_common_flags := --edition=2021 \ ...@@ -467,6 +467,7 @@ export rust_common_flags := --edition=2021 \
-Dclippy::let_unit_value -Dclippy::mut_mut \ -Dclippy::let_unit_value -Dclippy::mut_mut \
-Dclippy::needless_bitwise_bool \ -Dclippy::needless_bitwise_bool \
-Dclippy::needless_continue \ -Dclippy::needless_continue \
-Dclippy::no_mangle_with_rust_abi \
-Wclippy::dbg_macro -Wclippy::dbg_macro
KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS) KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS)
...@@ -1289,7 +1290,7 @@ prepare0: archprepare ...@@ -1289,7 +1290,7 @@ prepare0: archprepare
# All the preparing.. # All the preparing..
prepare: prepare0 prepare: prepare0
ifdef CONFIG_RUST ifdef CONFIG_RUST
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
$(Q)$(MAKE) $(build)=rust $(Q)$(MAKE) $(build)=rust
endif endif
...@@ -1825,7 +1826,7 @@ $(DOC_TARGETS): ...@@ -1825,7 +1826,7 @@ $(DOC_TARGETS):
# "Is Rust available?" target # "Is Rust available?" target
PHONY += rustavailable PHONY += rustavailable
rustavailable: rustavailable:
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v && echo "Rust is available!" $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh && echo "Rust is available!"
# Documentation target # Documentation target
# #
...@@ -1859,11 +1860,6 @@ rustfmt: ...@@ -1859,11 +1860,6 @@ rustfmt:
rustfmtcheck: rustfmt_flags = --check rustfmtcheck: rustfmt_flags = --check
rustfmtcheck: rustfmt rustfmtcheck: rustfmt
# IDE support targets
PHONY += rust-analyzer
rust-analyzer:
$(Q)$(MAKE) $(build)=rust $@
# Misc # Misc
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
...@@ -1924,6 +1920,7 @@ help: ...@@ -1924,6 +1920,7 @@ help:
@echo ' modules - default target, build the module(s)' @echo ' modules - default target, build the module(s)'
@echo ' modules_install - install the module' @echo ' modules_install - install the module'
@echo ' clean - remove generated files in module directory only' @echo ' clean - remove generated files in module directory only'
@echo ' rust-analyzer - generate rust-project.json rust-analyzer support file'
@echo '' @echo ''
__external_modules_error: __external_modules_error:
...@@ -2065,6 +2062,11 @@ quiet_cmd_tags = GEN $@ ...@@ -2065,6 +2062,11 @@ quiet_cmd_tags = GEN $@
tags TAGS cscope gtags: FORCE tags TAGS cscope gtags: FORCE
$(call cmd,tags) $(call cmd,tags)
# IDE support targets
PHONY += rust-analyzer
rust-analyzer:
$(Q)$(MAKE) $(build)=rust $@
# Script to generate missing namespace dependencies # Script to generate missing namespace dependencies
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
......
...@@ -329,7 +329,7 @@ quiet_cmd_bindgen = BINDGEN $@ ...@@ -329,7 +329,7 @@ quiet_cmd_bindgen = BINDGEN $@
$(BINDGEN) $< $(bindgen_target_flags) \ $(BINDGEN) $< $(bindgen_target_flags) \
--use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \ --use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \
--no-debug '.*' \ --no-debug '.*' \
--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE \ -o $@ -- $(bindgen_c_flags_final) -DMODULE \
$(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 = \
...@@ -349,8 +349,8 @@ $(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \ ...@@ -349,8 +349,8 @@ $(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \
# given it is `libclang`; but for consistency, future Clang changes and/or # given it is `libclang`; but for consistency, future Clang changes and/or
# a potential future GCC backend for `bindgen`, we disable it too. # a potential future GCC backend for `bindgen`, we disable it too.
$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_flags = \ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_flags = \
--blacklist-type '.*' --whitelist-var '' \ --blocklist-type '.*' --allowlist-var '' \
--whitelist-function 'rust_helper_.*' --allowlist-function 'rust_helper_.*'
$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_cflags = \ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_cflags = \
-I$(objtree)/$(obj) -Wno-missing-prototypes -Wno-missing-declarations -I$(objtree)/$(obj) -Wno-missing-prototypes -Wno-missing-declarations
$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extra = ; \ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extra = ; \
...@@ -402,12 +402,15 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L ...@@ -402,12 +402,15 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@)
rust-analyzer: rust-analyzer:
$(Q)$(srctree)/scripts/generate_rust_analyzer.py $(srctree) $(objtree) \ $(Q)$(srctree)/scripts/generate_rust_analyzer.py \
$(RUST_LIB_SRC) > $(objtree)/rust-project.json --cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \
$(abs_srctree) $(abs_objtree) \
$(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
$(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
redirect-intrinsics = \ redirect-intrinsics = \
__eqsf2 __gesf2 __lesf2 __nesf2 __unordsf2 \ __addsf3 __eqsf2 __gesf2 __lesf2 __ltsf2 __mulsf3 __nesf2 __unordsf2 \
__unorddf2 \ __adddf3 __ledf2 __ltdf2 __muldf3 __unorddf2 \
__muloti4 __multi3 \ __muloti4 __multi3 \
__udivmodti4 __udivti3 __umodti3 __udivmodti4 __udivti3 __umodti3
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#[doc(inline)] #[doc(inline)]
pub use core::alloc::*; pub use core::alloc::*;
use core::marker::Destruct;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
...@@ -41,6 +39,9 @@ ...@@ -41,6 +39,9 @@
#[rustc_allocator_zeroed] #[rustc_allocator_zeroed]
#[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;
} }
/// The global memory allocator. /// The global memory allocator.
...@@ -94,7 +95,14 @@ ...@@ -94,7 +95,14 @@
#[must_use = "losing the pointer will leak memory"] #[must_use = "losing the pointer will leak memory"]
#[inline] #[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 { pub unsafe fn alloc(layout: Layout) -> *mut u8 {
unsafe { __rust_alloc(layout.size(), layout.align()) } unsafe {
// Make sure we don't accidentally allow omitting the allocator shim in
// stable code until it is actually stabilized.
#[cfg(not(bootstrap))]
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
__rust_alloc(layout.size(), layout.align())
}
} }
/// Deallocate memory with the global allocator. /// Deallocate memory with the global allocator.
...@@ -333,16 +341,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { ...@@ -333,16 +341,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
#[cfg_attr(not(test), lang = "box_free")] #[cfg_attr(not(test), lang = "box_free")]
#[inline] #[inline]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
// This signature has to be the same as `Box`, otherwise an ICE will happen. // This signature has to be the same as `Box`, otherwise an ICE will happen.
// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
// well. // well.
// For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`, // For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well. // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Destruct>( pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
ptr: Unique<T>,
alloc: A,
) {
unsafe { unsafe {
let size = size_of_val(ptr.as_ref()); let size = size_of_val(ptr.as_ref());
let align = min_align_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref());
......
This diff is collapsed.
...@@ -89,35 +89,37 @@ ...@@ -89,35 +89,37 @@
#![warn(missing_debug_implementations)] #![warn(missing_debug_implementations)]
#![warn(missing_docs)] #![warn(missing_docs)]
#![allow(explicit_outlives_requirements)] #![allow(explicit_outlives_requirements)]
#![warn(multiple_supertrait_upcastable)]
// //
// Library features: // Library features:
// tidy-alphabetical-start
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
#![cfg_attr(test, feature(is_sorted))]
#![cfg_attr(test, feature(new_uninit))]
#![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_into_iter_constructors)]
#![feature(array_methods)] #![feature(array_methods)]
#![feature(array_windows)] #![feature(array_windows)]
#![feature(ascii_char)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(async_iterator)] #![feature(async_iterator)]
#![feature(coerce_unsized)] #![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![feature(const_align_of_val)]
#![feature(const_box)] #![feature(const_box)]
#![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_eval_select)]
#![feature(const_size_of_val)]
#![feature(const_align_of_val)]
#![feature(const_ptr_read)]
#![feature(const_maybe_uninit_zeroed)]
#![feature(const_maybe_uninit_write)]
#![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_write)]
#![feature(const_maybe_uninit_zeroed)]
#![feature(const_pin)]
#![feature(const_refs_to_cell)] #![feature(const_refs_to_cell)]
#![feature(const_size_of_val)]
#![feature(const_waker)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(core_panic)] #![feature(core_panic)]
#![feature(const_eval_select)]
#![feature(const_pin)]
#![feature(const_waker)]
#![feature(cstr_from_bytes_until_nul)]
#![feature(dispatch_from_dyn)] #![feature(dispatch_from_dyn)]
#![feature(error_generic_member_access)] #![feature(error_generic_member_access)]
#![feature(error_in_core)] #![feature(error_in_core)]
...@@ -128,7 +130,6 @@ ...@@ -128,7 +130,6 @@
#![feature(hasher_prefixfree_extras)] #![feature(hasher_prefixfree_extras)]
#![feature(inline_const)] #![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_next_chunk)]
#![feature(iter_repeat_n)] #![feature(iter_repeat_n)]
...@@ -136,8 +137,6 @@ ...@@ -136,8 +137,6 @@
#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_uninit_array_transpose)] #![feature(maybe_uninit_uninit_array_transpose)]
#![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(pattern)] #![feature(pattern)]
#![feature(pointer_byte_offsets)] #![feature(pointer_byte_offsets)]
#![feature(provide_any)] #![feature(provide_any)]
...@@ -153,6 +152,7 @@ ...@@ -153,6 +152,7 @@
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(slice_ptr_len)] #![feature(slice_ptr_len)]
#![feature(slice_range)] #![feature(slice_range)]
#![feature(std_internals)]
#![feature(str_internals)] #![feature(str_internals)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(trusted_len)] #![feature(trusted_len)]
...@@ -163,40 +163,42 @@ ...@@ -163,40 +163,42 @@
#![feature(unicode_internals)] #![feature(unicode_internals)]
#![feature(unsize)] #![feature(unsize)]
#![feature(utf8_chunks)] #![feature(utf8_chunks)]
#![feature(std_internals)] // tidy-alphabetical-end
// //
// Language features: // Language features:
// tidy-alphabetical-start
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(panic_update_hook))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_internals)] #![feature(allocator_internals)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(c_unwind)]
#![feature(cfg_sanitize)] #![feature(cfg_sanitize)]
#![feature(const_deref)]
#![feature(const_mut_refs)] #![feature(const_mut_refs)]
#![feature(const_ptr_write)]
#![feature(const_precise_live_drops)] #![feature(const_precise_live_drops)]
#![feature(const_ptr_write)]
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(const_try)] #![feature(const_try)]
#![feature(dropck_eyepatch)] #![feature(dropck_eyepatch)]
#![feature(exclusive_range_pattern)] #![feature(exclusive_range_pattern)]
#![feature(fundamental)] #![feature(fundamental)]
#![cfg_attr(not(test), feature(generator_trait))]
#![feature(hashmap_internals)] #![feature(hashmap_internals)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(multiple_supertrait_upcastable)]
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(never_type)] #![feature(never_type)]
#![feature(pointer_is_aligned)]
#![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)] #![feature(stmt_expr_attributes)]
#![cfg_attr(test, feature(test))]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(unsized_fn_params)] #![feature(unsized_fn_params)]
#![feature(c_unwind)]
#![feature(with_negative_coherence)] #![feature(with_negative_coherence)]
#![cfg_attr(test, feature(panic_update_hook))] // tidy-alphabetical-end
// //
// Rustdoc features: // Rustdoc features:
#![feature(doc_cfg)] #![feature(doc_cfg)]
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
use core::cmp; use core::cmp;
use core::intrinsics; use core::intrinsics;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::ops::Drop;
use core::ptr::{self, NonNull, Unique}; use core::ptr::{self, NonNull, Unique};
use core::slice; use core::slice;
...@@ -274,10 +273,15 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> { ...@@ -274,10 +273,15 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
if T::IS_ZST || 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 could use Layout::array here which ensures the absence of isize and usize overflows
// checks to get our current layout. // and could hypothetically handle differences between stride and size, but this memory
// has already been allocated so we know it can't overflow and currently rust does not
// support such types. So we can do better by skipping some checks and avoid an unwrap.
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
unsafe { unsafe {
let layout = Layout::array::<T>(self.cap).unwrap_unchecked(); let align = mem::align_of::<T>();
let size = mem::size_of::<T>().unchecked_mul(self.cap);
let layout = Layout::from_size_align_unchecked(size, align);
Some((self.ptr.cast().into(), layout)) Some((self.ptr.cast().into(), layout))
} }
} }
...@@ -465,11 +469,13 @@ fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { ...@@ -465,11 +469,13 @@ 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");
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
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
let ptr = unsafe { let ptr = unsafe {
// `Layout::array` cannot overflow here because it would have // `Layout::array` cannot overflow here because it would have
// overflowed earlier when capacity was larger. // overflowed earlier when capacity was larger.
let new_layout = Layout::array::<T>(cap).unwrap_unchecked(); let new_size = mem::size_of::<T>().unchecked_mul(cap);
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
self.alloc self.alloc
.shrink(ptr, layout, new_layout) .shrink(ptr, layout, new_layout)
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
......
...@@ -784,6 +784,38 @@ fn borrow_mut(&mut self) -> &mut [T] { ...@@ -784,6 +784,38 @@ fn borrow_mut(&mut self) -> &mut [T] {
} }
} }
// Specializable trait for implementing ToOwned::clone_into. This is
// public in the crate and has the Allocator parameter so that
// vec::clone_from use it too.
#[cfg(not(no_global_oom_handling))]
pub(crate) trait SpecCloneIntoVec<T, A: Allocator> {
fn clone_into(&self, target: &mut Vec<T, A>);
}
#[cfg(not(no_global_oom_handling))]
impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
default fn clone_into(&self, target: &mut Vec<T, A>) {
// drop anything in target that will not be overwritten
target.truncate(self.len());
// target.len <= self.len due to the truncate above, so the
// slices here are always in-bounds.
let (init, tail) = self.split_at(target.len());
// reuse the contained values' allocations/resources.
target.clone_from_slice(init);
target.extend_from_slice(tail);
}
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
fn clone_into(&self, target: &mut Vec<T, A>) {
target.clear();
target.extend_from_slice(self);
}
}
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> ToOwned for [T] { impl<T: Clone> ToOwned for [T] {
...@@ -799,16 +831,7 @@ fn to_owned(&self) -> Vec<T> { ...@@ -799,16 +831,7 @@ fn to_owned(&self) -> Vec<T> {
} }
fn clone_into(&self, target: &mut Vec<T>) { fn clone_into(&self, target: &mut Vec<T>) {
// drop anything in target that will not be overwritten SpecCloneIntoVec::clone_into(self, target);
target.truncate(self.len());
// target.len <= self.len due to the truncate above, so the
// slices here are always in-bounds.
let (init, tail) = self.split_at(target.len());
// reuse the contained values' allocations/resources.
target.clone_from_slice(init);
target.extend_from_slice(tail);
} }
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
/// ///
/// ``` /// ```
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let iter: std::vec::Drain<_> = v.drain(..); /// let iter: std::vec::Drain<'_, _> = v.drain(..);
/// ``` /// ```
#[stable(feature = "drain", since = "1.6.0")] #[stable(feature = "drain", since = "1.6.0")]
pub struct Drain< pub struct Drain<
...@@ -114,9 +114,7 @@ pub fn keep_rest(self) { ...@@ -114,9 +114,7 @@ pub fn keep_rest(self) {
let unyielded_ptr = this.iter.as_slice().as_ptr(); let unyielded_ptr = this.iter.as_slice().as_ptr();
// ZSTs have no identity, so we don't need to move them around. // ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0; if !T::IS_ZST {
if needs_move {
let start_ptr = source_vec.as_mut_ptr().add(start); let start_ptr = source_vec.as_mut_ptr().add(start);
// memmove back unyielded elements // memmove back unyielded elements
...@@ -199,7 +197,7 @@ fn drop(&mut self) { ...@@ -199,7 +197,7 @@ fn drop(&mut self) {
} }
} }
let iter = mem::replace(&mut self.iter, (&mut []).iter()); let iter = mem::take(&mut self.iter);
let drop_len = iter.len(); let drop_len = iter.len();
let mut vec = self.vec; let mut vec = self.vec;
......
// 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::{self, ManuallyDrop}; use core::mem::{ManuallyDrop, SizedTypeProperties};
use core::ptr; use core::ptr;
use core::slice; use core::slice;
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
/// #![feature(drain_filter)] /// #![feature(drain_filter)]
/// ///
/// 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::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
/// ``` /// ```
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
#[derive(Debug)] #[derive(Debug)]
...@@ -98,9 +98,7 @@ pub fn keep_rest(self) { ...@@ -98,9 +98,7 @@ pub fn keep_rest(self) {
unsafe { unsafe {
// ZSTs have no identity, so we don't need to move them around. // ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0; if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
if needs_move && this.idx < this.old_len && this.del > 0 {
let ptr = this.vec.as_mut_ptr(); let ptr = this.vec.as_mut_ptr();
let src = ptr.add(this.idx); let src = ptr.add(this.idx);
let dst = src.sub(this.del); let dst = src.sub(this.del);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::num::NonZeroUsize;
#[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};
...@@ -109,7 +110,7 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] { ...@@ -109,7 +110,7 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] {
/// ``` /// ```
/// # 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()); /// 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(drop);
/// std::mem::forget(into_iter); /// std::mem::forget(into_iter);
/// ``` /// ```
/// ///
...@@ -215,7 +216,7 @@ fn size_hint(&self) -> (usize, Option<usize>) { ...@@ -215,7 +216,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
} }
#[inline] #[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> { fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
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 T::IS_ZST { if T::IS_ZST {
...@@ -229,10 +230,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> { ...@@ -229,10 +230,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
unsafe { unsafe {
ptr::drop_in_place(to_drop); ptr::drop_in_place(to_drop);
} }
if step_size < n { NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
return Err(step_size);
}
Ok(())
} }
#[inline] #[inline]
...@@ -315,7 +313,7 @@ fn next_back(&mut self) -> Option<T> { ...@@ -315,7 +313,7 @@ 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<(), NonZeroUsize> {
let step_size = self.len().min(n); let step_size = self.len().min(n);
if T::IS_ZST { if T::IS_ZST {
// SAFETY: same as for advance_by() // SAFETY: same as for advance_by()
...@@ -329,10 +327,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { ...@@ -329,10 +327,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
unsafe { unsafe {
ptr::drop_in_place(to_drop); ptr::drop_in_place(to_drop);
} }
if step_size < n { NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
return Err(step_size);
}
Ok(())
} }
} }
...@@ -349,6 +344,24 @@ impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} ...@@ -349,6 +344,24 @@ impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
#[stable(feature = "default_iters", since = "1.70.0")]
impl<T, A> Default for IntoIter<T, A>
where
A: Allocator + Default,
{
/// Creates an empty `vec::IntoIter`.
///
/// ```
/// # use std::vec;
/// let iter: vec::IntoIter<u8> = Default::default();
/// assert_eq!(iter.len(), 0);
/// assert_eq!(iter.as_slice(), &[]);
/// ```
fn default() -> Self {
super::Vec::new_in(Default::default()).into_iter()
}
}
#[doc(hidden)] #[doc(hidden)]
#[unstable(issue = "none", feature = "std_internals")] #[unstable(issue = "none", feature = "std_internals")]
#[rustc_unsafe_specialization_marker] #[rustc_unsafe_specialization_marker]
......
...@@ -58,13 +58,9 @@ ...@@ -58,13 +58,9 @@
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use core::cmp; use core::cmp;
use core::cmp::Ordering; use core::cmp::Ordering;
use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
use core::intrinsics::assume;
use core::iter; use core::iter;
#[cfg(not(no_global_oom_handling))]
use core::iter::FromIterator;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ops::{self, Index, IndexMut, Range, RangeBounds};
...@@ -381,8 +377,8 @@ ...@@ -381,8 +377,8 @@
/// Currently, `Vec` does not guarantee the order in which elements are dropped. /// Currently, `Vec` does not guarantee the order in which elements are dropped.
/// The order has changed in the past and may change again. /// The order has changed in the past and may change again.
/// ///
/// [`get`]: ../../std/vec/struct.Vec.html#method.get /// [`get`]: slice::get
/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut /// [`get_mut`]: slice::get_mut
/// [`String`]: crate::string::String /// [`String`]: crate::string::String
/// [`&str`]: type@str /// [`&str`]: type@str
/// [`shrink_to_fit`]: Vec::shrink_to_fit /// [`shrink_to_fit`]: Vec::shrink_to_fit
...@@ -708,14 +704,14 @@ pub const fn new_in(alloc: A) -> Self { ...@@ -708,14 +704,14 @@ pub const fn new_in(alloc: A) -> Self {
/// ///
/// // The vector contains no items, even though it has capacity for more /// // The vector contains no items, even though it has capacity for more
/// assert_eq!(vec.len(), 0); /// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// ///
/// // These are all done without reallocating... /// // These are all done without reallocating...
/// for i in 0..10 { /// for i in 0..10 {
/// vec.push(i); /// vec.push(i);
/// } /// }
/// assert_eq!(vec.len(), 10); /// assert_eq!(vec.len(), 10);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// ///
/// // ...but this may make the vector reallocate /// // ...but this may make the vector reallocate
/// vec.push(11); /// vec.push(11);
...@@ -766,14 +762,14 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { ...@@ -766,14 +762,14 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
/// ///
/// // The vector contains no items, even though it has capacity for more /// // The vector contains no items, even though it has capacity for more
/// assert_eq!(vec.len(), 0); /// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// ///
/// // These are all done without reallocating... /// // These are all done without reallocating...
/// for i in 0..10 { /// for i in 0..10 {
/// vec.push(i); /// vec.push(i);
/// } /// }
/// assert_eq!(vec.len(), 10); /// assert_eq!(vec.len(), 10);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// ///
/// // ...but this may make the vector reallocate /// // ...but this may make the vector reallocate
/// vec.push(11); /// vec.push(11);
...@@ -999,7 +995,7 @@ pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) { ...@@ -999,7 +995,7 @@ pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
/// ``` /// ```
/// let mut vec: Vec<i32> = Vec::with_capacity(10); /// let mut vec: Vec<i32> = Vec::with_capacity(10);
/// vec.push(42); /// vec.push(42);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
...@@ -1150,7 +1146,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE ...@@ -1150,7 +1146,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE
/// ``` /// ```
/// let mut vec = Vec::with_capacity(10); /// let mut vec = Vec::with_capacity(10);
/// vec.extend([1, 2, 3]); /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// vec.shrink_to_fit(); /// vec.shrink_to_fit();
/// assert!(vec.capacity() >= 3); /// assert!(vec.capacity() >= 3);
/// ``` /// ```
...@@ -1177,7 +1173,7 @@ pub fn shrink_to_fit(&mut self) { ...@@ -1177,7 +1173,7 @@ pub fn shrink_to_fit(&mut self) {
/// ``` /// ```
/// let mut vec = Vec::with_capacity(10); /// let mut vec = Vec::with_capacity(10);
/// vec.extend([1, 2, 3]); /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// vec.shrink_to(4); /// vec.shrink_to(4);
/// assert!(vec.capacity() >= 4); /// assert!(vec.capacity() >= 4);
/// vec.shrink_to(0); /// vec.shrink_to(0);
...@@ -1212,7 +1208,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) { ...@@ -1212,7 +1208,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
/// let mut vec = Vec::with_capacity(10); /// let mut vec = Vec::with_capacity(10);
/// vec.extend([1, 2, 3]); /// vec.extend([1, 2, 3]);
/// ///
/// assert_eq!(vec.capacity(), 10); /// assert!(vec.capacity() >= 10);
/// let slice = vec.into_boxed_slice(); /// let slice = vec.into_boxed_slice();
/// assert_eq!(slice.into_vec().capacity(), 3); /// assert_eq!(slice.into_vec().capacity(), 3);
/// ``` /// ```
...@@ -1358,11 +1354,7 @@ pub fn as_mut_slice(&mut self) -> &mut [T] { ...@@ -1358,11 +1354,7 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
pub fn as_ptr(&self) -> *const T { pub fn as_ptr(&self) -> *const T {
// We shadow the slice method of the same name to avoid going through // We shadow the slice method of the same name to avoid going through
// `deref`, which creates an intermediate reference. // `deref`, which creates an intermediate reference.
let ptr = self.buf.ptr(); self.buf.ptr()
unsafe {
assume(!ptr.is_null());
}
ptr
} }
/// Returns an unsafe mutable pointer to the vector's buffer, or a dangling /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
...@@ -1395,11 +1387,7 @@ pub fn as_ptr(&self) -> *const T { ...@@ -1395,11 +1387,7 @@ pub fn as_ptr(&self) -> *const T {
pub fn as_mut_ptr(&mut self) -> *mut T { pub fn as_mut_ptr(&mut self) -> *mut T {
// We shadow the slice method of the same name to avoid going through // We shadow the slice method of the same name to avoid going through
// `deref_mut`, which creates an intermediate reference. // `deref_mut`, which creates an intermediate reference.
let ptr = self.buf.ptr(); self.buf.ptr()
unsafe {
assume(!ptr.is_null());
}
ptr
} }
/// Returns a reference to the underlying allocator. /// Returns a reference to the underlying allocator.
...@@ -2891,35 +2879,6 @@ fn deref_mut(&mut self) -> &mut [T] { ...@@ -2891,35 +2879,6 @@ fn deref_mut(&mut self) -> &mut [T] {
} }
} }
#[cfg(not(no_global_oom_handling))]
trait SpecCloneFrom {
fn clone_from(this: &mut Self, other: &Self);
}
#[cfg(not(no_global_oom_handling))]
impl<T: Clone, A: Allocator> SpecCloneFrom for Vec<T, A> {
default fn clone_from(this: &mut Self, other: &Self) {
// drop anything that will not be overwritten
this.truncate(other.len());
// self.len <= other.len due to the truncate above, so the
// slices here are always in-bounds.
let (init, tail) = other.split_at(this.len());
// reuse the contained values' allocations/resources.
this.clone_from_slice(init);
this.extend_from_slice(tail);
}
}
#[cfg(not(no_global_oom_handling))]
impl<T: Copy, A: Allocator> SpecCloneFrom for Vec<T, A> {
fn clone_from(this: &mut Self, other: &Self) {
this.clear();
this.extend_from_slice(other);
}
}
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
...@@ -2940,7 +2899,7 @@ fn clone(&self) -> Self { ...@@ -2940,7 +2899,7 @@ fn clone(&self) -> Self {
} }
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, other: &Self) {
SpecCloneFrom::clone_from(self, other) crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self);
} }
} }
...@@ -2948,7 +2907,6 @@ fn clone_from(&mut self, other: &Self) { ...@@ -2948,7 +2907,6 @@ fn clone_from(&mut self, other: &Self) {
/// as required by the `core::borrow::Borrow` implementation. /// as required by the `core::borrow::Borrow` implementation.
/// ///
/// ``` /// ```
/// #![feature(build_hasher_simple_hash_one)]
/// use std::hash::BuildHasher; /// use std::hash::BuildHasher;
/// ///
/// let b = std::collections::hash_map::RandomState::new(); /// let b = std::collections::hash_map::RandomState::new();
...@@ -3330,7 +3288,7 @@ fn extend_reserve(&mut self, additional: usize) { ...@@ -3330,7 +3288,7 @@ fn extend_reserve(&mut self, additional: usize) {
} }
} }
/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison).
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> { impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
#[inline] #[inline]
...@@ -3342,7 +3300,7 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> { ...@@ -3342,7 +3300,7 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, A: Allocator> Eq for Vec<T, A> {} impl<T: Eq, A: Allocator> Eq for Vec<T, A> {}
/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). /// Implements ordering of vectors, [lexicographically](Ord#lexicographical-comparison).
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord, A: Allocator> Ord for Vec<T, A> { impl<T: Ord, A: Allocator> Ord for Vec<T, A> {
#[inline] #[inline]
...@@ -3365,8 +3323,7 @@ fn drop(&mut self) { ...@@ -3365,8 +3323,7 @@ fn drop(&mut self) {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] impl<T> Default for Vec<T> {
impl<T> const Default for Vec<T> {
/// Creates an empty `Vec<T>`. /// Creates an empty `Vec<T>`.
/// ///
/// The vector will not allocate until elements are pushed onto it. /// The vector will not allocate until elements are pushed onto it.
...@@ -3462,10 +3419,7 @@ fn from(s: &mut [T]) -> Vec<T> { ...@@ -3462,10 +3419,7 @@ fn from(s: &mut [T]) -> Vec<T> {
/// ``` /// ```
#[cfg(not(test))] #[cfg(not(test))]
fn from(s: [T; N]) -> Vec<T> { fn from(s: [T; N]) -> Vec<T> {
<[T]>::into_vec( <[T]>::into_vec(Box::new(s))
#[rustc_box]
Box::new(s),
)
} }
#[cfg(test)] #[cfg(test)]
...@@ -3490,8 +3444,8 @@ impl<'a, T> From<Cow<'a, [T]>> for Vec<T> ...@@ -3490,8 +3444,8 @@ impl<'a, T> From<Cow<'a, [T]>> for Vec<T>
/// ///
/// ``` /// ```
/// # use std::borrow::Cow; /// # use std::borrow::Cow;
/// let o: Cow<[i32]> = Cow::Owned(vec![1, 2, 3]); /// let o: Cow<'_, [i32]> = Cow::Owned(vec![1, 2, 3]);
/// let b: Cow<[i32]> = Cow::Borrowed(&[1, 2, 3]); /// let b: Cow<'_, [i32]> = Cow::Borrowed(&[1, 2, 3]);
/// assert_eq!(Vec::from(o), Vec::from(b)); /// assert_eq!(Vec::from(o), Vec::from(b));
/// ``` /// ```
fn from(s: Cow<'a, [T]>) -> Vec<T> { fn from(s: Cow<'a, [T]>) -> Vec<T> {
......
...@@ -37,14 +37,21 @@ pub extern "C" fn $ident() { ...@@ -37,14 +37,21 @@ pub extern "C" fn $ident() {
); );
define_panicking_intrinsics!("`f32` should not be used", { define_panicking_intrinsics!("`f32` should not be used", {
__addsf3,
__eqsf2, __eqsf2,
__gesf2, __gesf2,
__lesf2, __lesf2,
__ltsf2,
__mulsf3,
__nesf2, __nesf2,
__unordsf2, __unordsf2,
}); });
define_panicking_intrinsics!("`f64` should not be used", { define_panicking_intrinsics!("`f64` should not be used", {
__adddf3,
__ledf2,
__ltdf2,
__muldf3,
__unorddf2, __unorddf2,
}); });
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
* *
* All symbols are exported as GPL-only to guarantee no GPL-only feature is * All symbols are exported as GPL-only to guarantee no GPL-only feature is
* accidentally exposed. * accidentally exposed.
*
* Sorted alphabetically.
*/ */
#include <kunit/test-bug.h> #include <kunit/test-bug.h>
...@@ -23,10 +25,10 @@ ...@@ -23,10 +25,10 @@
#include <linux/build_bug.h> #include <linux/build_bug.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errname.h> #include <linux/errname.h>
#include <linux/refcount.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/spinlock.h> #include <linux/refcount.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/spinlock.h>
#include <linux/wait.h> #include <linux/wait.h>
__noreturn void rust_helper_BUG(void) __noreturn void rust_helper_BUG(void)
...@@ -143,19 +145,18 @@ struct kunit *rust_helper_kunit_get_current_test(void) ...@@ -143,19 +145,18 @@ struct kunit *rust_helper_kunit_get_current_test(void)
EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test); EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test);
/* /*
* We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
* as the Rust `usize` type, so we can use it in contexts where Rust * use it in contexts where Rust expects a `usize` like slice (array) indices.
* expects a `usize` like slice (array) indices. `usize` is defined to be * `usize` is defined to be the same as C's `uintptr_t` type (can hold any
* the same as C's `uintptr_t` type (can hold any pointer) but not * pointer) but not necessarily the same as `size_t` (can hold the size of any
* necessarily the same as `size_t` (can hold the size of any single * single object). Most modern platforms use the same concrete integer type for
* object). Most modern platforms use the same concrete integer type for
* both of them, but in case we find ourselves on a platform where * both of them, but in case we find ourselves on a platform where
* that's not true, fail early instead of risking ABI or * that's not true, fail early instead of risking ABI or
* integer-overflow issues. * integer-overflow issues.
* *
* If your platform fails this assertion, it means that you are in * If your platform fails this assertion, it means that you are in
* danger of integer-overflow bugs (even if you attempt to remove * danger of integer-overflow bugs (even if you attempt to add
* `--size_t-is-usize`). It may be easiest to change the kernel ABI on * `--no-size_t-is-usize`). It may be easiest to change the kernel ABI on
* your platform such that `size_t` matches `uintptr_t` (i.e., to increase * your platform such that `size_t` matches `uintptr_t` (i.e., to increase
* `size_t`, because `uintptr_t` has to be at least as big as `size_t`). * `size_t`, because `uintptr_t` has to be at least as big as `size_t`).
*/ */
......
...@@ -41,9 +41,9 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf ...@@ -41,9 +41,9 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf
unsafe impl GlobalAlloc for KernelAllocator { unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// `krealloc()` is used instead of `kmalloc()` because the latter is // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
// an inline function and cannot be bound to as a result. // requirement.
unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 } unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) }
} }
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
...@@ -51,58 +51,38 @@ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { ...@@ -51,58 +51,38 @@ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
bindings::kfree(ptr as *const core::ffi::c_void); bindings::kfree(ptr as *const core::ffi::c_void);
} }
} }
}
#[global_allocator]
static ALLOCATOR: KernelAllocator = KernelAllocator;
// `rustc` only generates these for some crate types. Even then, we would need
// to extract the object file that has them from the archive. For the moment,
// let's generate them ourselves instead.
//
// Note: Although these are *safe* functions, they are called by the compiler
// with parameters that obey the same `GlobalAlloc` function safety
// requirements: size and align should form a valid layout, and size is
// greater than 0.
//
// Note that `#[no_mangle]` implies exported too, nowadays.
#[no_mangle]
fn __rust_alloc(size: usize, align: usize) -> *mut u8 {
// SAFETY: See assumption above.
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
// SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
// than 0. // SAFETY:
unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } // - `new_size`, when rounded up to the nearest multiple of `layout.align()`, will not
} // overflow `isize` by the function safety requirement.
// - `layout.align()` is a proper alignment (i.e. not zero and must be a power of two).
let layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
// SAFETY:
// - `ptr` is either null or a pointer allocated by this allocator by the function safety
// requirement.
// - the size of `layout` is not zero because `new_size` is not zero by the function safety
// requirement.
unsafe { krealloc_aligned(ptr, layout, bindings::GFP_KERNEL) }
}
#[no_mangle] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) { // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety
unsafe { bindings::kfree(ptr as *const core::ffi::c_void) }; // requirement.
unsafe {
krealloc_aligned(
ptr::null_mut(),
layout,
bindings::GFP_KERNEL | bindings::__GFP_ZERO,
)
}
}
} }
#[no_mangle] #[global_allocator]
fn __rust_realloc(ptr: *mut u8, _old_size: usize, align: usize, new_size: usize) -> *mut u8 { static ALLOCATOR: KernelAllocator = KernelAllocator;
// SAFETY: See assumption above.
let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, align) };
// SAFETY: Per assumption above, `ptr` is allocated by `__rust_*` before, and the size of
// `new_layout` is greater than 0.
unsafe { krealloc_aligned(ptr, new_layout, bindings::GFP_KERNEL) }
}
// See <https://github.com/rust-lang/rust/pull/86844>.
#[no_mangle] #[no_mangle]
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 { static __rust_no_alloc_shim_is_unstable: u8 = 0;
// SAFETY: See assumption above.
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
// SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater
// than 0.
unsafe {
krealloc_aligned(
ptr::null_mut(),
layout,
bindings::GFP_KERNEL | bindings::__GFP_ZERO,
)
}
}
This diff is collapsed.
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
/// ///
/// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
/// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns
type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>; pub(super) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>;
/// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this
/// type, since the closure needs to fulfill the same safety requirement as the /// type, since the closure needs to fulfill the same safety requirement as the
...@@ -32,6 +32,18 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { ...@@ -32,6 +32,18 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
} }
} }
// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the
// `__pinned_init` invariants.
unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
#[inline]
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
(self.0)(slot)
}
}
/// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate
/// the pin projections within the initializers. /// the pin projections within the initializers.
/// ///
...@@ -174,7 +186,6 @@ pub fn init<E>(self: Pin<&mut Self>, init: impl PinInit<T, E>) -> Result<Pin<&mu ...@@ -174,7 +186,6 @@ pub fn init<E>(self: Pin<&mut Self>, init: impl PinInit<T, E>) -> Result<Pin<&mu
/// Can be forgotten to prevent the drop. /// Can be forgotten to prevent the drop.
pub struct DropGuard<T: ?Sized> { pub struct DropGuard<T: ?Sized> {
ptr: *mut T, ptr: *mut T,
do_drop: Cell<bool>,
} }
impl<T: ?Sized> DropGuard<T> { impl<T: ?Sized> DropGuard<T> {
...@@ -190,32 +201,16 @@ impl<T: ?Sized> DropGuard<T> { ...@@ -190,32 +201,16 @@ impl<T: ?Sized> DropGuard<T> {
/// - will not be dropped by any other means. /// - will not be dropped by any other means.
#[inline] #[inline]
pub unsafe fn new(ptr: *mut T) -> Self { pub unsafe fn new(ptr: *mut T) -> Self {
Self { Self { ptr }
ptr,
do_drop: Cell::new(true),
}
}
/// Prevents this guard from dropping the supplied pointer.
///
/// # Safety
///
/// This function is unsafe in order to prevent safe code from forgetting this guard. It should
/// only be called by the macros in this module.
#[inline]
pub unsafe fn forget(&self) {
self.do_drop.set(false);
} }
} }
impl<T: ?Sized> Drop for DropGuard<T> { impl<T: ?Sized> Drop for DropGuard<T> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
if self.do_drop.get() { // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function
// SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function // ensuring that this operation is safe.
// ensuring that this operation is safe. unsafe { ptr::drop_in_place(self.ptr) }
unsafe { ptr::drop_in_place(self.ptr) }
}
} }
} }
......
This diff is collapsed.
...@@ -95,7 +95,4 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! { ...@@ -95,7 +95,4 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
pr_emerg!("{}\n", info); pr_emerg!("{}\n", info);
// SAFETY: FFI call. // SAFETY: FFI call.
unsafe { bindings::BUG() }; unsafe { bindings::BUG() };
// Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
// instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
loop {}
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
pub use alloc::{boxed::Box, vec::Vec}; pub use alloc::{boxed::Box, vec::Vec};
#[doc(no_inline)] #[doc(no_inline)]
pub use macros::{module, pin_data, pinned_drop, vtable}; pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable};
pub use super::build_assert; pub use super::build_assert;
......
...@@ -72,8 +72,8 @@ unsafe fn relock(ptr: *mut Self::State, guard_state: &mut Self::GuardState) { ...@@ -72,8 +72,8 @@ unsafe fn relock(ptr: *mut Self::State, guard_state: &mut Self::GuardState) {
/// A mutual exclusion primitive. /// A mutual exclusion primitive.
/// ///
/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock backend /// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock
/// specified as the generic parameter `B`. /// [`Backend`] specified as the generic parameter `B`.
#[pin_data] #[pin_data]
pub struct Lock<T: ?Sized, B: Backend> { pub struct Lock<T: ?Sized, B: Backend> {
/// The kernel lock object. /// The kernel lock object.
...@@ -126,7 +126,7 @@ pub fn lock(&self) -> Guard<'_, T, B> { ...@@ -126,7 +126,7 @@ pub fn lock(&self) -> Guard<'_, T, B> {
/// A lock guard. /// A lock guard.
/// ///
/// Allows mutual exclusion primitives that implement the `Backend` trait to automatically unlock /// Allows mutual exclusion primitives that implement the [`Backend`] trait to automatically unlock
/// when a guard goes out of scope. It also provides a safe and convenient way to access the data /// when a guard goes out of scope. It also provides a safe and convenient way to access the data
/// protected by the lock. /// protected by the lock.
#[must_use = "the lock unlocks immediately when the guard is unused"] #[must_use = "the lock unlocks immediately when the guard is unused"]
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
use alloc::boxed::Box; use alloc::boxed::Box;
use core::{ use core::{
cell::UnsafeCell, cell::UnsafeCell,
marker::PhantomData, marker::{PhantomData, PhantomPinned},
mem::MaybeUninit, mem::MaybeUninit,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
ptr::NonNull, ptr::NonNull,
...@@ -206,17 +206,26 @@ fn drop(&mut self) { ...@@ -206,17 +206,26 @@ fn drop(&mut self) {
/// ///
/// This is meant to be used with FFI objects that are never interpreted by Rust code. /// This is meant to be used with FFI objects that are never interpreted by Rust code.
#[repr(transparent)] #[repr(transparent)]
pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>); pub struct Opaque<T> {
value: UnsafeCell<MaybeUninit<T>>,
_pin: PhantomPinned,
}
impl<T> Opaque<T> { impl<T> Opaque<T> {
/// Creates a new opaque value. /// Creates a new opaque value.
pub const fn new(value: T) -> Self { pub const fn new(value: T) -> Self {
Self(MaybeUninit::new(UnsafeCell::new(value))) Self {
value: UnsafeCell::new(MaybeUninit::new(value)),
_pin: PhantomPinned,
}
} }
/// Creates an uninitialised value. /// Creates an uninitialised value.
pub const fn uninit() -> Self { pub const fn uninit() -> Self {
Self(MaybeUninit::uninit()) Self {
value: UnsafeCell::new(MaybeUninit::uninit()),
_pin: PhantomPinned,
}
} }
/// Creates a pin-initializer from the given initializer closure. /// Creates a pin-initializer from the given initializer closure.
...@@ -240,7 +249,7 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit<Self> { ...@@ -240,7 +249,7 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit<Self> {
/// Returns a raw pointer to the opaque data. /// Returns a raw pointer to the opaque data.
pub fn get(&self) -> *mut T { pub fn get(&self) -> *mut T {
UnsafeCell::raw_get(self.0.as_ptr()) UnsafeCell::get(&self.value).cast::<T>()
} }
/// Gets the value behind `this`. /// Gets the value behind `this`.
...@@ -248,7 +257,7 @@ pub fn get(&self) -> *mut T { ...@@ -248,7 +257,7 @@ pub fn get(&self) -> *mut T {
/// This function is useful to get access to the value without creating intermediate /// This function is useful to get access to the value without creating intermediate
/// references. /// references.
pub const fn raw_get(this: *const Self) -> *mut T { pub const fn raw_get(this: *const Self) -> *mut T {
UnsafeCell::raw_get(this.cast::<UnsafeCell<T>>()) UnsafeCell::raw_get(this.cast::<UnsafeCell<MaybeUninit<T>>>()).cast::<T>()
} }
} }
......
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
mod concat_idents; mod concat_idents;
mod helpers; mod helpers;
mod module; mod module;
mod paste;
mod pin_data; mod pin_data;
mod pinned_drop; mod pinned_drop;
mod vtable; mod vtable;
mod zeroable;
use proc_macro::TokenStream; use proc_macro::TokenStream;
...@@ -246,3 +248,118 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { ...@@ -246,3 +248,118 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
pinned_drop::pinned_drop(args, input) pinned_drop::pinned_drop(args, input)
} }
/// Paste identifiers together.
///
/// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a
/// single identifier.
///
/// This is similar to the [`paste`] crate, but with pasting feature limited to identifiers
/// (literals, lifetimes and documentation strings are not supported). There is a difference in
/// supported modifiers as well.
///
/// # Example
///
/// ```ignore
/// use kernel::macro::paste;
///
/// macro_rules! pub_no_prefix {
/// ($prefix:ident, $($newname:ident),+) => {
/// paste! {
/// $(pub(crate) const $newname: u32 = [<$prefix $newname>];)+
/// }
/// };
/// }
///
/// pub_no_prefix!(
/// binder_driver_return_protocol_,
/// BR_OK,
/// BR_ERROR,
/// BR_TRANSACTION,
/// BR_REPLY,
/// BR_DEAD_REPLY,
/// BR_TRANSACTION_COMPLETE,
/// BR_INCREFS,
/// BR_ACQUIRE,
/// BR_RELEASE,
/// BR_DECREFS,
/// BR_NOOP,
/// BR_SPAWN_LOOPER,
/// BR_DEAD_BINDER,
/// BR_CLEAR_DEATH_NOTIFICATION_DONE,
/// BR_FAILED_REPLY
/// );
///
/// assert_eq!(BR_OK, binder_driver_return_protocol_BR_OK);
/// ```
///
/// # Modifiers
///
/// For each identifier, it is possible to attach one or multiple modifiers to
/// it.
///
/// Currently supported modifiers are:
/// * `span`: change the span of concatenated identifier to the span of the specified token. By
/// default the span of the `[< >]` group is used.
/// * `lower`: change the identifier to lower case.
/// * `upper`: change the identifier to upper case.
///
/// ```ignore
/// use kernel::macro::paste;
///
/// macro_rules! pub_no_prefix {
/// ($prefix:ident, $($newname:ident),+) => {
/// kernel::macros::paste! {
/// $(pub(crate) const fn [<$newname:lower:span>]: u32 = [<$prefix $newname:span>];)+
/// }
/// };
/// }
///
/// pub_no_prefix!(
/// binder_driver_return_protocol_,
/// BR_OK,
/// BR_ERROR,
/// BR_TRANSACTION,
/// BR_REPLY,
/// BR_DEAD_REPLY,
/// BR_TRANSACTION_COMPLETE,
/// BR_INCREFS,
/// BR_ACQUIRE,
/// BR_RELEASE,
/// BR_DECREFS,
/// BR_NOOP,
/// BR_SPAWN_LOOPER,
/// BR_DEAD_BINDER,
/// BR_CLEAR_DEATH_NOTIFICATION_DONE,
/// BR_FAILED_REPLY
/// );
///
/// assert_eq!(br_ok(), binder_driver_return_protocol_BR_OK);
/// ```
///
/// [`paste`]: https://docs.rs/paste/
#[proc_macro]
pub fn paste(input: TokenStream) -> TokenStream {
let mut tokens = input.into_iter().collect();
paste::expand(&mut tokens);
tokens.into_iter().collect()
}
/// Derives the [`Zeroable`] trait for the given struct.
///
/// This can only be used for structs where every field implements the [`Zeroable`] trait.
///
/// # Examples
///
/// ```rust,ignore
/// #[derive(Zeroable)]
/// pub struct DriverData {
/// id: i64,
/// buf_ptr: *mut u8,
/// len: usize,
/// }
/// ```
#[proc_macro_derive(Zeroable)]
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
zeroable::derive(input)
}
...@@ -199,7 +199,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { ...@@ -199,7 +199,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
/// Used by the printing macros, e.g. [`info!`]. /// Used by the printing macros, e.g. [`info!`].
const __LOG_PREFIX: &[u8] = b\"{name}\\0\"; const __LOG_PREFIX: &[u8] = b\"{name}\\0\";
/// The \"Rust loadable module\" mark, for `scripts/is_rust_module.sh`. /// The \"Rust loadable module\" mark.
// //
// This may be best done another way later on, e.g. as a new modinfo // This may be best done another way later on, e.g. as a new modinfo
// key or a new section. For the moment, keep it simple. // key or a new section. For the moment, keep it simple.
......
// SPDX-License-Identifier: GPL-2.0
use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree};
fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree {
let mut tokens = tokens.iter();
let mut segments = Vec::new();
let mut span = None;
loop {
match tokens.next() {
None => break,
Some(TokenTree::Literal(lit)) => segments.push((lit.to_string(), lit.span())),
Some(TokenTree::Ident(ident)) => {
let mut value = ident.to_string();
if value.starts_with("r#") {
value.replace_range(0..2, "");
}
segments.push((value, ident.span()));
}
Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
let Some(TokenTree::Ident(ident)) = tokens.next() else {
panic!("expected identifier as modifier");
};
let (mut value, sp) = segments.pop().expect("expected identifier before modifier");
match ident.to_string().as_str() {
// Set the overall span of concatenated token as current span
"span" => {
assert!(
span.is_none(),
"span modifier should only appear at most once"
);
span = Some(sp);
}
"lower" => value = value.to_lowercase(),
"upper" => value = value.to_uppercase(),
v => panic!("unknown modifier `{v}`"),
};
segments.push((value, sp));
}
_ => panic!("unexpected token in paste segments"),
};
}
let pasted: String = segments.into_iter().map(|x| x.0).collect();
TokenTree::Ident(Ident::new(&pasted, span.unwrap_or(group_span)))
}
pub(crate) fn expand(tokens: &mut Vec<TokenTree>) {
for token in tokens.iter_mut() {
if let TokenTree::Group(group) = token {
let delimiter = group.delimiter();
let span = group.span();
let mut stream: Vec<_> = group.stream().into_iter().collect();
// Find groups that looks like `[< A B C D >]`
if delimiter == Delimiter::Bracket
&& stream.len() >= 3
&& matches!(&stream[0], TokenTree::Punct(p) if p.as_char() == '<')
&& matches!(&stream[stream.len() - 1], TokenTree::Punct(p) if p.as_char() == '>')
{
// Replace the group with concatenated token
*token = concat(&stream[1..stream.len() - 1], span);
} else {
// Recursively expand tokens inside the group
expand(&mut stream);
let mut group = Group::new(delimiter, stream.into_iter().collect());
group.set_span(span);
*token = TokenTree::Group(group);
}
}
}
// Path segments cannot contain invisible delimiter group, so remove them if any.
for i in (0..tokens.len().saturating_sub(3)).rev() {
// Looking for a double colon
if matches!(
(&tokens[i + 1], &tokens[i + 2]),
(TokenTree::Punct(a), TokenTree::Punct(b))
if a.as_char() == ':' && a.spacing() == Spacing::Joint && b.as_char() == ':'
) {
match &tokens[i + 3] {
TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
tokens.splice(i + 3..i + 4, group.stream());
}
_ => (),
}
match &tokens[i] {
TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
tokens.splice(i..i + 1, group.stream());
}
_ => (),
}
}
}
}
...@@ -124,6 +124,18 @@ macro_rules! quote_spanned { ...@@ -124,6 +124,18 @@ macro_rules! quote_spanned {
)); ));
quote_spanned!(@proc $v $span $($tt)*); quote_spanned!(@proc $v $span $($tt)*);
}; };
(@proc $v:ident $span:ident ; $($tt:tt)*) => {
$v.push(::proc_macro::TokenTree::Punct(
::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
));
quote_spanned!(@proc $v $span $($tt)*);
};
(@proc $v:ident $span:ident + $($tt:tt)*) => {
$v.push(::proc_macro::TokenTree::Punct(
::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone)
));
quote_spanned!(@proc $v $span $($tt)*);
};
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => { (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span))); $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
quote_spanned!(@proc $v $span $($tt)*); quote_spanned!(@proc $v $span $($tt)*);
......
// SPDX-License-Identifier: GPL-2.0
use crate::helpers::{parse_generics, Generics};
use proc_macro::{TokenStream, TokenTree};
pub(crate) fn derive(input: TokenStream) -> TokenStream {
let (
Generics {
impl_generics,
ty_generics,
},
mut rest,
) = parse_generics(input);
// This should be the body of the struct `{...}`.
let last = rest.pop();
// Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`.
let mut new_impl_generics = Vec::with_capacity(impl_generics.len());
// Are we inside of a generic where we want to add `Zeroable`?
let mut in_generic = !impl_generics.is_empty();
// Have we already inserted `Zeroable`?
let mut inserted = false;
// Level of `<>` nestings.
let mut nested = 0;
for tt in impl_generics {
match &tt {
// If we find a `,`, then we have finished a generic/constant/lifetime parameter.
TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {
if in_generic && !inserted {
new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
}
in_generic = true;
inserted = false;
new_impl_generics.push(tt);
}
// If we find `'`, then we are entering a lifetime.
TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => {
in_generic = false;
new_impl_generics.push(tt);
}
TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {
new_impl_generics.push(tt);
if in_generic {
new_impl_generics.extend(quote! { ::kernel::init::Zeroable + });
inserted = true;
}
}
TokenTree::Punct(p) if p.as_char() == '<' => {
nested += 1;
new_impl_generics.push(tt);
}
TokenTree::Punct(p) if p.as_char() == '>' => {
assert!(nested > 0);
nested -= 1;
new_impl_generics.push(tt);
}
_ => new_impl_generics.push(tt),
}
}
assert_eq!(nested, 0);
if in_generic && !inserted {
new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });
}
quote! {
::kernel::__derive_zeroable!(
parse_input:
@sig(#(#rest)*),
@impl_generics(#(#new_impl_generics)*),
@ty_generics(#(#ty_generics)*),
@body(#last),
);
}
}
...@@ -41,8 +41,6 @@ quiet_cmd_btf_ko = BTF [M] $@ ...@@ -41,8 +41,6 @@ quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \ cmd_btf_ko = \
if [ ! -f vmlinux ]; then \ if [ ! -f vmlinux ]; then \
printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \
elif [ -n "$(CONFIG_RUST)" ] && $(srctree)/scripts/is_rust_module.sh $@; then \
printf "Skipping BTF generation for %s because it's a Rust module\n" $@ 1>&2; \
else \ else \
LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \
$(RESOLVE_BTFIDS) -b vmlinux $@; \ $(RESOLVE_BTFIDS) -b vmlinux $@; \
......
...@@ -6,10 +6,19 @@ ...@@ -6,10 +6,19 @@
import argparse import argparse
import json import json
import logging import logging
import os
import pathlib import pathlib
import sys import sys
def generate_crates(srctree, objtree, sysroot_src): def args_crates_cfgs(cfgs):
crates_cfgs = {}
for cfg in cfgs:
crate, vals = cfg.split("=", 1)
crates_cfgs[crate] = vals.replace("--cfg", "").split()
return crates_cfgs
def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
# Generate the configuration list. # Generate the configuration list.
cfg = [] cfg = []
with open(objtree / "include" / "generated" / "rustc_cfg") as fd: with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
...@@ -23,6 +32,7 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -23,6 +32,7 @@ def generate_crates(srctree, objtree, sysroot_src):
# Avoid O(n^2) iterations by keeping a map of indexes. # Avoid O(n^2) iterations by keeping a map of indexes.
crates = [] crates = []
crates_indexes = {} crates_indexes = {}
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
crates_indexes[display_name] = len(crates) crates_indexes[display_name] = len(crates)
...@@ -44,6 +54,7 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -44,6 +54,7 @@ def generate_crates(srctree, objtree, sysroot_src):
"core", "core",
sysroot_src / "core" / "src" / "lib.rs", sysroot_src / "core" / "src" / "lib.rs",
[], [],
cfg=crates_cfgs.get("core", []),
is_workspace_member=False, is_workspace_member=False,
) )
...@@ -57,6 +68,7 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -57,6 +68,7 @@ def generate_crates(srctree, objtree, sysroot_src):
"alloc", "alloc",
srctree / "rust" / "alloc" / "lib.rs", srctree / "rust" / "alloc" / "lib.rs",
["core", "compiler_builtins"], ["core", "compiler_builtins"],
cfg=crates_cfgs.get("alloc", []),
) )
append_crate( append_crate(
...@@ -65,7 +77,7 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -65,7 +77,7 @@ def generate_crates(srctree, objtree, sysroot_src):
[], [],
is_proc_macro=True, is_proc_macro=True,
) )
crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so" crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so"
append_crate( append_crate(
"build_error", "build_error",
...@@ -95,19 +107,26 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -95,19 +107,26 @@ def generate_crates(srctree, objtree, sysroot_src):
"exclude_dirs": [], "exclude_dirs": [],
} }
def is_root_crate(build_file, target):
try:
return f"{target}.o" in open(build_file).read()
except FileNotFoundError:
return False
# Then, the rest outside of `rust/`. # Then, the rest outside of `rust/`.
# #
# We explicitly mention the top-level folders we want to cover. # We explicitly mention the top-level folders we want to cover.
for folder in ("samples", "drivers"): extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers"))
for path in (srctree / folder).rglob("*.rs"): if external_src is not None:
extra_dirs = [external_src]
for folder in extra_dirs:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path) logging.info("Checking %s", path)
name = path.name.replace(".rs", "") name = path.name.replace(".rs", "")
# Skip those that are not crate roots. # Skip those that are not crate roots.
try: if not is_root_crate(path.parent / "Makefile", name) and \
if f"{name}.o" not in open(path.parent / "Makefile").read(): not is_root_crate(path.parent / "Kbuild", name):
continue
except FileNotFoundError:
continue continue
logging.info("Adding %s", name) logging.info("Adding %s", name)
...@@ -123,9 +142,11 @@ def generate_crates(srctree, objtree, sysroot_src): ...@@ -123,9 +142,11 @@ def generate_crates(srctree, objtree, sysroot_src):
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--cfgs', action='append', default=[])
parser.add_argument("srctree", type=pathlib.Path) parser.add_argument("srctree", type=pathlib.Path)
parser.add_argument("objtree", type=pathlib.Path) parser.add_argument("objtree", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path) parser.add_argument("sysroot_src", type=pathlib.Path)
parser.add_argument("exttree", type=pathlib.Path, nargs="?")
args = parser.parse_args() args = parser.parse_args()
logging.basicConfig( logging.basicConfig(
...@@ -134,7 +155,7 @@ def main(): ...@@ -134,7 +155,7 @@ def main():
) )
rust_project = { rust_project = {
"crates": generate_crates(args.srctree, args.objtree, args.sysroot_src), "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs),
"sysroot_src": str(args.sysroot_src), "sysroot_src": str(args.sysroot_src),
} }
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# is_rust_module.sh module.ko
#
# Returns `0` if `module.ko` is a Rust module, `1` otherwise.
set -e
# Using the `16_` prefix ensures other symbols with the same substring
# are not picked up (even if it would be unlikely). The last part is
# used just in case LLVM decides to use the `.` suffix.
#
# In the future, checking for the `.comment` section may be another
# option, see https://github.com/rust-lang/rust/pull/97550.
${NM} "$*" | grep -qE '^[0-9a-fA-F]+ [Rr] _R[^[:space:]]+16___IS_RUST_MODULE[^[:space:]]*$'
...@@ -31,10 +31,10 @@ llvm) ...@@ -31,10 +31,10 @@ llvm)
fi fi
;; ;;
rustc) rustc)
echo 1.68.2 echo 1.71.1
;; ;;
bindgen) bindgen)
echo 0.56.0 echo 0.65.1
;; ;;
*) *)
echo "$1: unknown tool" >&2 echo "$1: unknown tool" >&2
......
This diff is collapsed.
This diff is collapsed.
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