From: Weilong Chen chenweilong@huawei.com
maillist inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I5J75G CVE: NA
--------------------------------
The version of openeuler is different from the latest version of the mainline, so need adapted
Signed-off-by: Weilong Chen chenweilong@huawei.com --- rust/alloc/alloc.rs | 8 +- rust/alloc/borrow.rs | 8 +- rust/alloc/boxed.rs | 59 ++++++---- rust/alloc/boxed/thin.rs | 217 ++++++++++++++++++++++++++++++++++++ rust/alloc/fmt.rs | 55 +++++---- rust/alloc/lib.rs | 17 ++- rust/alloc/macros.rs | 3 +- rust/alloc/raw_vec.rs | 16 +-- rust/alloc/slice.rs | 27 +++-- rust/alloc/str.rs | 11 +- rust/alloc/string.rs | 101 ++++++++++++++--- rust/compiler_builtins.rs | 24 +++- rust/helpers.c | 4 +- rust/kernel/amba.rs | 5 +- rust/kernel/device.rs | 2 +- rust/kernel/file.rs | 4 + rust/kernel/irq.rs | 2 +- rust/kernel/net.rs | 5 +- rust/kernel/net/filter.rs | 12 +- rust/kernel/print.rs | 4 +- rust/kernel/random.rs | 4 +- samples/rust/Makefile | 1 - scripts/cc-version.sh | 72 ++++++++++++ scripts/kconfig/confdata.c | 156 +++++++++++++++++++++++++- scripts/min-tool-version.sh | 43 +++++++ 25 files changed, 757 insertions(+), 103 deletions(-) create mode 100644 rust/alloc/boxed/thin.rs create mode 100755 scripts/cc-version.sh create mode 100755 scripts/min-tool-version.sh
diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs index cea3b747673f..ca224a541770 100644 --- a/rust/alloc/alloc.rs +++ b/rust/alloc/alloc.rs @@ -16,6 +16,8 @@ use core::ptr::{self, NonNull}; #[doc(inline)] pub use core::alloc::*;
+use core::marker::Destruct; + #[cfg(test)] mod tests;
@@ -331,7 +333,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { // 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) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Drop>( +pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Destruct>( ptr: Unique<T>, alloc: A, ) { @@ -387,7 +389,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { #[cfg(all(not(no_global_oom_handling), test))] pub use std::alloc::handle_alloc_error;
-#[cfg(all(not(no_global_oom_handling), not(any(target_os = "hermit", test))))] +#[cfg(all(not(no_global_oom_handling), not(test)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] @@ -399,7 +401,7 @@ pub mod __alloc_error_handler { // if there is no `#[alloc_error_handler]` #[rustc_std_internal_symbol] pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! { - panic!("memory allocation of {} bytes failed", size) + panic!("memory allocation of {size} bytes failed") }
// if there is an `#[alloc_error_handler]` diff --git a/rust/alloc/borrow.rs b/rust/alloc/borrow.rs index 8e1d8a764641..ca8e3dfa7004 100644 --- a/rust/alloc/borrow.rs +++ b/rust/alloc/borrow.rs @@ -163,7 +163,7 @@ where /// let readonly = [1, 2]; /// let borrowed = Items::new((&readonly[..]).into()); /// match borrowed { -/// Items { values: Cow::Borrowed(b) } => println!("borrowed {:?}", b), +/// Items { values: Cow::Borrowed(b) } => println!("borrowed {b:?}"), /// _ => panic!("expect borrowed value"), /// } /// @@ -294,8 +294,7 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> { /// /// # Examples /// - /// Calling `into_owned` on a `Cow::Borrowed` clones the underlying data - /// and becomes a `Cow::Owned`: + /// Calling `into_owned` on a `Cow::Borrowed` returns a clone of the borrowed data: /// /// ``` /// use std::borrow::Cow; @@ -309,7 +308,8 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> { /// ); /// ``` /// - /// Calling `into_owned` on a `Cow::Owned` is a no-op: + /// Calling `into_owned` on a `Cow::Owned` returns the owned data. The data is moved out of the + /// `Cow` without being cloned. /// /// ``` /// use std::borrow::Cow; diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs index 921fcef75e4b..8fd296421dec 100644 --- a/rust/alloc/boxed.rs +++ b/rust/alloc/boxed.rs @@ -33,7 +33,7 @@ //! } //! //! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); -//! println!("{:?}", list); +//! println!("{list:?}"); //! ``` //! //! This will print `Cons(1, Cons(2, Nil))`. @@ -145,7 +145,7 @@ use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; use core::iter::{FusedIterator, Iterator}; -use core::marker::{Unpin, Unsize}; +use core::marker::{Destruct, Unpin, Unsize}; use core::mem; use core::ops::{ CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver, @@ -165,6 +165,11 @@ use crate::str::from_boxed_utf8_unchecked; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec;
+#[unstable(feature = "thin_box", issue = "92791")] +pub use thin::ThinBox; + +mod thin; + /// A pointer type for heap allocation. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. @@ -353,7 +358,7 @@ impl<T, A: Allocator> Box<T, A> { #[inline] pub const fn new_in(x: T, alloc: A) -> Self where - A: ~const Allocator + ~const Drop, + A: ~const Allocator + ~const Destruct, { let mut boxed = Self::new_uninit_in(alloc); unsafe { @@ -382,8 +387,8 @@ impl<T, A: Allocator> Box<T, A> { #[inline] pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> where - T: ~const Drop, - A: ~const Allocator + ~const Drop, + T: ~const Destruct, + A: ~const Allocator + ~const Destruct, { let mut boxed = Self::try_new_uninit_in(alloc)?; unsafe { @@ -419,7 +424,7 @@ impl<T, A: Allocator> Box<T, A> { // #[unstable(feature = "new_uninit", issue = "63291")] pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> where - A: ~const Allocator + ~const Drop, + A: ~const Allocator + ~const Destruct, { let layout = Layout::new::<mem::MaybeUninit<T>>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. @@ -457,7 +462,7 @@ impl<T, A: Allocator> Box<T, A> { #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> where - A: ~const Allocator + ~const Drop, + A: ~const Allocator + ~const Destruct, { let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = alloc.allocate(layout)?.cast(); @@ -491,7 +496,7 @@ impl<T, A: Allocator> Box<T, A> { #[must_use] pub const fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> where - A: ~const Allocator + ~const Drop, + A: ~const Allocator + ~const Destruct, { let layout = Layout::new::<mem::MaybeUninit<T>>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. @@ -529,7 +534,7 @@ impl<T, A: Allocator> Box<T, A> { #[rustc_const_unstable(feature = "const_box", issue = "92521")] pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> where - A: ~const Allocator + ~const Drop, + A: ~const Allocator + ~const Destruct, { let layout = Layout::new::<mem::MaybeUninit<T>>(); let ptr = alloc.allocate_zeroed(layout)?.cast(); @@ -545,7 +550,7 @@ impl<T, A: Allocator> Box<T, A> { #[inline(always)] pub const fn pin_in(x: T, alloc: A) -> Pin<Self> where - A: 'static + ~const Allocator + ~const Drop, + A: 'static + ~const Allocator + ~const Destruct, { Self::into_pin(Self::new_in(x, alloc)) } @@ -576,7 +581,7 @@ impl<T, A: Allocator> Box<T, A> { #[inline] pub const fn into_inner(boxed: Self) -> T where - Self: ~const Drop, + Self: ~const Destruct, { *boxed } @@ -1189,17 +1194,25 @@ impl<T: Default> Default for Box<T> {
#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Default for Box<[T]> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for Box<[T]> { fn default() -> Self { - Box::<[T; 0]>::new([]) + let ptr: Unique<[T]> = Unique::<[T; 0]>::dangling(); + Box(ptr, Global) } }
#[cfg(not(no_global_oom_handling))] #[stable(feature = "default_box_extra", since = "1.17.0")] -impl Default for Box<str> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl const Default for Box<str> { fn default() -> Self { - unsafe { from_boxed_utf8_unchecked(Default::default()) } + // SAFETY: This is the same as `Unique::cast<U>` but with an unsized `U = str`. + let ptr: Unique<str> = unsafe { + let bytes: Unique<[u8]> = Unique::<[u8; 0]>::dangling(); + Unique::new_unchecked(bytes.as_ptr() as *mut str) + }; + Box(ptr, Global) } }
@@ -1358,6 +1371,12 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> { fn write_isize(&mut self, i: isize) { (**self).write_isize(i) } + fn write_length_prefix(&mut self, len: usize) { + (**self).write_length_prefix(len) + } + fn write_str(&mut self, s: &str) { + (**self).write_str(s) + } }
#[cfg(not(no_global_oom_handling))] @@ -1409,7 +1428,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> { /// let slice: &[u8] = &[104, 101, 108, 108, 111]; /// let boxed_slice: Box<[u8]> = Box::from(slice); /// - /// println!("{:?}", boxed_slice); + /// println!("{boxed_slice:?}"); /// ``` fn from(slice: &[T]) -> Box<[T]> { let len = slice.len(); @@ -1451,7 +1470,7 @@ impl From<&str> for Box<str> { /// /// ```rust /// let boxed: Box<str> = Box::from("hello"); - /// println!("{}", boxed); + /// println!("{boxed}"); /// ``` #[inline] fn from(s: &str) -> Box<str> { @@ -1476,14 +1495,14 @@ impl From<Cow<'_, str>> for Box<str> { /// /// let unboxed = Cow::Borrowed("hello"); /// let boxed: Box<str> = Box::from(unboxed); - /// println!("{}", boxed); + /// println!("{boxed}"); /// ``` /// /// ```rust /// # use std::borrow::Cow; /// let unboxed = Cow::Owned("hello".to_string()); /// let boxed: Box<str> = Box::from(unboxed); - /// println!("{}", boxed); + /// println!("{boxed}"); /// ``` #[inline] fn from(cow: Cow<'_, str>) -> Box<str> { @@ -1530,7 +1549,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> { /// /// ```rust /// let boxed: Box<[u8]> = Box::from([4, 2]); - /// println!("{:?}", boxed); + /// println!("{boxed:?}"); /// ``` fn from(array: [T; N]) -> Box<[T]> { box array diff --git a/rust/alloc/boxed/thin.rs b/rust/alloc/boxed/thin.rs new file mode 100644 index 000000000000..db7a3e91aa80 --- /dev/null +++ b/rust/alloc/boxed/thin.rs @@ -0,0 +1,217 @@ +// Based on +// https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943a... +// by matthieu-m +use crate::alloc::{self, Layout, LayoutError}; +use core::fmt::{self, Debug, Display, Formatter}; +use core::marker::PhantomData; +#[cfg(not(no_global_oom_handling))] +use core::marker::Unsize; +use core::mem; +use core::ops::{Deref, DerefMut}; +use core::ptr::Pointee; +use core::ptr::{self, NonNull}; + +/// ThinBox. +/// +/// A thin pointer for heap allocation, regardless of T. +/// +/// # Examples +/// +/// ``` +/// #![feature(thin_box)] +/// use std::boxed::ThinBox; +/// +/// let five = ThinBox::new(5); +/// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]); +/// +/// use std::mem::{size_of, size_of_val}; +/// let size_of_ptr = size_of::<*const ()>(); +/// assert_eq!(size_of_ptr, size_of_val(&five)); +/// assert_eq!(size_of_ptr, size_of_val(&thin_slice)); +/// ``` +#[unstable(feature = "thin_box", issue = "92791")] +pub struct ThinBox<T: ?Sized> { + ptr: WithHeader<<T as Pointee>::Metadata>, + _marker: PhantomData<T>, +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T> ThinBox<T> { + /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on + /// the stack. + /// + /// # Examples + /// + /// ``` + /// #![feature(thin_box)] + /// use std::boxed::ThinBox; + /// + /// let five = ThinBox::new(5); + /// ``` + #[cfg(not(no_global_oom_handling))] + pub fn new(value: T) -> Self { + let meta = ptr::metadata(&value); + let ptr = WithHeader::new(meta, value); + ThinBox { ptr, _marker: PhantomData } + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<Dyn: ?Sized> ThinBox<Dyn> { + /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on + /// the stack. + /// + /// # Examples + /// + /// ``` + /// #![feature(thin_box)] + /// use std::boxed::ThinBox; + /// + /// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]); + /// ``` + #[cfg(not(no_global_oom_handling))] + pub fn new_unsize<T>(value: T) -> Self + where + T: Unsize<Dyn>, + { + let meta = ptr::metadata(&value as &Dyn); + let ptr = WithHeader::new(meta, value); + ThinBox { ptr, _marker: PhantomData } + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized + Debug> Debug for ThinBox<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(self.deref(), f) + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized + Display> Display for ThinBox<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self.deref(), f) + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized> Deref for ThinBox<T> { + type Target = T; + + fn deref(&self) -> &T { + let value = self.data(); + let metadata = self.meta(); + let pointer = ptr::from_raw_parts(value as *const (), metadata); + unsafe { &*pointer } + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized> DerefMut for ThinBox<T> { + fn deref_mut(&mut self) -> &mut T { + let value = self.data(); + let metadata = self.meta(); + let pointer = ptr::from_raw_parts_mut::<T>(value as *mut (), metadata); + unsafe { &mut *pointer } + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized> Drop for ThinBox<T> { + fn drop(&mut self) { + unsafe { + let value = self.deref_mut(); + let value = value as *mut T; + self.ptr.drop::<T>(value); + } + } +} + +#[unstable(feature = "thin_box", issue = "92791")] +impl<T: ?Sized> ThinBox<T> { + fn meta(&self) -> <T as Pointee>::Metadata { + // Safety: + // - NonNull and valid. + unsafe { *self.ptr.header() } + } + + fn data(&self) -> *mut u8 { + self.ptr.value() + } +} + +/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location. +struct WithHeader<H>(NonNull<u8>, PhantomData<H>); + +impl<H> WithHeader<H> { + #[cfg(not(no_global_oom_handling))] + fn new<T>(header: H, value: T) -> WithHeader<H> { + let value_layout = Layout::new::<T>(); + let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else { + // We pass an empty layout here because we do not know which layout caused the + // arithmetic overflow in `Layout::extend` and `handle_alloc_error` takes `Layout` as + // its argument rather than `Result<Layout, LayoutError>`, also this function has been + // stable since 1.28 ._. + // + // On the other hand, look at this gorgeous turbofish! + alloc::handle_alloc_error(Layout::new::<()>()); + }; + + unsafe { + let ptr = alloc::alloc(layout); + + if ptr.is_null() { + alloc::handle_alloc_error(layout); + } + // Safety: + // - The size is at least `aligned_header_size`. + let ptr = ptr.add(value_offset) as *mut _; + + let ptr = NonNull::new_unchecked(ptr); + + let result = WithHeader(ptr, PhantomData); + ptr::write(result.header(), header); + ptr::write(result.value().cast(), value); + + result + } + } + + // Safety: + // - Assumes that `value` can be dereferenced. + unsafe fn drop<T: ?Sized>(&self, value: *mut T) { + unsafe { + // SAFETY: Layout must have been computable if we're in drop + let (layout, value_offset) = + Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked(); + + ptr::drop_in_place::<T>(value); + // We only drop the value because the Pointee trait requires that the metadata is copy + // aka trivially droppable + alloc::dealloc(self.0.as_ptr().sub(value_offset), layout); + } + } + + fn header(&self) -> *mut H { + // Safety: + // - At least `size_of::<H>()` bytes are allocated ahead of the pointer. + // - We know that H will be aligned because the middle pointer is aligned to the greater + // of the alignment of the header and the data and the header size includes the padding + // needed to align the header. Subtracting the header size from the aligned data pointer + // will always result in an aligned header pointer, it just may not point to the + // beginning of the allocation. + unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H } + } + + fn value(&self) -> *mut u8 { + self.0.as_ptr() + } + + const fn header_size() -> usize { + mem::size_of::<H>() + } + + fn alloc_layout(value_layout: Layout) -> Result<(Layout, usize), LayoutError> { + Layout::new::<H>().extend(value_layout) + } +} diff --git a/rust/alloc/fmt.rs b/rust/alloc/fmt.rs index be75e6637442..b9c4d2926d23 100644 --- a/rust/alloc/fmt.rs +++ b/rust/alloc/fmt.rs @@ -223,10 +223,12 @@ //! //! 3. An asterisk `.*`: //! -//! `.*` means that this `{...}` is associated with *two* format inputs rather than one: the -//! first input holds the `usize` precision, and the second holds the value to print. Note that -//! in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers -//! to the *value* to print, and the `precision` must come in the input preceding `<arg>`. +//! `.*` means that this `{...}` is associated with *two* format inputs rather than one: +//! - If a format string in the fashion of `{:<spec>.*}` is used, then the first input holds +//! the `usize` precision, and the second holds the value to print. +//! - If a format string in the fashion of `{<arg>:<spec>.*}` is used, then the `<arg>` part +//! refers to the value to print, and the `precision` is taken like it was specified with an +//! omitted positional parameter (`{}` instead of `{<arg>:}`). //! //! For example, the following calls all print the same thing `Hello x is 0.01000`: //! @@ -240,15 +242,19 @@ //! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)} //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01); //! -//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision -//! // specified in first of next two args (5)} +//! // Hello {next arg -> arg 0 ("x")} is {second of next two args -> arg 2 (0.01) with precision +//! // specified in first of next two args -> arg 1 (5)} //! println!("Hello {} is {:.*}", "x", 5, 0.01); //! -//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision -//! // specified in its predecessor (5)} +//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision +//! // specified in next arg -> arg 0 (5)} +//! println!("Hello {1} is {2:.*}", 5, "x", 0.01); +//! +//! // Hello {next arg -> arg 0 ("x")} is {arg 2 (0.01) with precision +//! // specified in next arg -> arg 1 (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); //! -//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified +//! // Hello {next arg -> arg 0 ("x")} is {arg "number" (0.01) with precision specified //! // in arg "prec" (5)} //! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); //! ``` @@ -306,7 +312,7 @@ //! ```text //! format_string := text [ maybe_format text ] * //! maybe_format := '{' '{' | '}' '}' | format -//! format := '{' [ argument ] [ ':' format_spec ] '}' +//! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}' //! argument := integer | identifier //! //! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type @@ -319,7 +325,12 @@ //! count := parameter | integer //! parameter := argument '$' //! ``` -//! In the above grammar, `text` must not contain any `'{'` or `'}'` characters. +//! In the above grammar, +//! - `text` must not contain any `'{'` or `'}'` characters, +//! - `ws` is any character for which [`char::is_whitespace`] returns `true`, has no semantic +//! meaning and is completely optional, +//! - `integer` is a decimal integer that may contain leading zeroes and +//! - `identifier` is an `IDENTIFIER_OR_KEYWORD` (not an `IDENTIFIER`) as defined by the [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html). //! //! # Formatting traits //! @@ -360,9 +371,9 @@ //! ``` //! //! Your type will be passed as `self` by-reference, and then the function -//! should emit output into the `f.buf` stream. It is up to each format trait -//! implementation to correctly adhere to the requested formatting parameters. -//! The values of these parameters will be listed in the fields of the +//! should emit output into the Formatter `f` which implements `fmt::Write`. It is up to each +//! format trait implementation to correctly adhere to the requested formatting parameters. +//! The values of these parameters can be accessed with methods of the //! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also //! provides some helper methods. //! @@ -418,9 +429,9 @@ //! fn main() { //! let myvector = Vector2D { x: 3, y: 4 }; //! -//! println!("{}", myvector); // => "(3, 4)" -//! println!("{:?}", myvector); // => "Vector2D {x: 3, y:4}" -//! println!("{:10.3b}", myvector); // => " 5.000" +//! println!("{myvector}"); // => "(3, 4)" +//! println!("{myvector:?}"); // => "Vector2D {x: 3, y:4}" +//! println!("{myvector:10.3b}"); // => " 5.000" //! } //! ``` //! @@ -451,7 +462,7 @@ //! //! ```ignore (only-for-syntax-highlight) //! format! // described above -//! write! // first argument is a &mut io::Write, the destination +//! write! // first argument is either a &mut io::Write or a &mut fmt::Write, the destination //! writeln! // same as write but appends a newline //! print! // the format string is printed to the standard output //! println! // same as print but appends a newline @@ -462,11 +473,11 @@ //! //! ### `write!` //! -//! This and [`writeln!`] are two macros which are used to emit the format string +//! [`write!`] and [`writeln!`] are two macros which are used to emit the format string //! to a specified stream. This is used to prevent intermediate allocations of //! format strings and instead directly write the output. Under the hood, this //! function is actually invoking the [`write_fmt`] function defined on the -//! [`std::io::Write`] trait. Example usage is: +//! [`std::io::Write`] and the [`std::fmt::Write`] trait. Example usage is: //! //! ``` //! # #![allow(unused_must_use)] @@ -493,7 +504,7 @@ //! //! ### `format_args!` //! -//! This is a curious macro used to safely pass around +//! [`format_args!`] is a curious macro used to safely pass around //! an opaque object describing the format string. This object //! does not require any heap allocations to create, and it only //! references information on the stack. Under the hood, all of @@ -531,10 +542,12 @@ //! [`to_string`]: crate::string::ToString::to_string "ToString::to_string" //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt //! [`std::io::Write`]: ../../std/io/trait.Write.html +//! [`std::fmt::Write`]: ../../std/fmt/trait.Write.html //! [`print!`]: ../../std/macro.print.html "print!" //! [`println!`]: ../../std/macro.println.html "println!" //! [`eprint!`]: ../../std/macro.eprint.html "eprint!" //! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!" +//! [`format_args!`]: ../../std/macro.format_args.html "format_args!" //! [`fmt::Arguments`]: Arguments "fmt::Arguments" //! [`format`]: format() "fmt::format"
diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs index 085dc005170a..03d2ce1df814 100644 --- a/rust/alloc/lib.rs +++ b/rust/alloc/lib.rs @@ -88,11 +88,13 @@ #![allow(explicit_outlives_requirements)] // // Library features: +#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] +#![feature(assert_matches)] #![feature(async_iterator)] #![feature(coerce_unsized)] #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] @@ -106,14 +108,18 @@ #![feature(const_maybe_uninit_write)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_refs_to_cell)] +#![feature(core_c_str)] #![feature(core_intrinsics)] +#![feature(core_ffi_c)] #![feature(const_eval_select)] #![feature(const_pin)] +#![feature(cstr_from_bytes_until_nul)] #![feature(dispatch_from_dyn)] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] +#![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(layout_for_ptr)] @@ -122,6 +128,8 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] #![feature(ptr_internals)] +#![feature(ptr_metadata)] +#![feature(ptr_sub_ptr)] #![feature(receiver_trait)] #![feature(set_ptr_value)] #![feature(slice_group_by)] @@ -129,9 +137,11 @@ #![feature(slice_ptr_len)] #![feature(slice_range)] #![feature(str_internals)] +#![feature(strict_provenance)] #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] +#![feature(unchecked_math)] #![feature(unicode_internals)] #![feature(unsize)] // @@ -141,9 +151,7 @@ #![feature(associated_type_bounds)] #![feature(box_syntax)] #![feature(cfg_sanitize)] -#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))] #![feature(const_deref)] -#![feature(const_fn_trait_bound)] #![feature(const_mut_refs)] #![feature(const_ptr_write)] #![feature(const_precise_live_drops)] @@ -153,13 +161,16 @@ #![feature(exclusive_range_pattern)] #![feature(fundamental)] #![cfg_attr(not(test), feature(generator_trait))] +#![feature(hashmap_internals)] #![feature(lang_items)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] // Not necessary, but here to test the `nll` feature. #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] +#![feature(slice_internals)] #![feature(staged_api)] #![cfg_attr(test, feature(test))] #![feature(unboxed_closures)] @@ -205,6 +216,8 @@ mod boxed { } pub mod borrow; pub mod collections; +#[cfg(not(no_global_oom_handling))] +pub mod ffi; pub mod fmt; #[cfg(not(no_rc))] pub mod rc; diff --git a/rust/alloc/macros.rs b/rust/alloc/macros.rs index 47ebcd5277d1..fa7bacfd5847 100644 --- a/rust/alloc/macros.rs +++ b/rust/alloc/macros.rs @@ -57,7 +57,8 @@ macro_rules! vec { // required for this macro definition, is not available. Instead use the // `slice::into_vec` function which is only available with cfg(test) // NB see the slice::hack module in slice.rs for more information -#[cfg(test)] +#[cfg(all(not(no_global_oom_handling), test))] +#[cfg_attr(not(bootstrap), allow(unused_macro_rules))] macro_rules! vec { () => ( $crate::vec::Vec::new() diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs index 018c4657f580..59e353bfe5d3 100644 --- a/rust/alloc/raw_vec.rs +++ b/rust/alloc/raw_vec.rs @@ -120,7 +120,6 @@ impl<T, A: Allocator> RawVec<T, A> {
/// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } @@ -177,7 +176,8 @@ impl<T, A: Allocator> RawVec<T, A> {
#[cfg(not(no_global_oom_handling))] fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { - if mem::size_of::<T>() == 0 { + // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if mem::size_of::<T>() == 0 || capacity == 0 { Self::new_in(alloc) } else { // We avoid `unwrap_or_else` here because it bloats the amount of @@ -211,7 +211,8 @@ impl<T, A: Allocator> RawVec<T, A> { }
fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> { - if mem::size_of::<T>() == 0 { + // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if mem::size_of::<T>() == 0 || capacity == 0 { return Ok(Self::new_in(alloc)); }
@@ -276,9 +277,7 @@ impl<T, A: Allocator> RawVec<T, A> { // We have an allocated chunk of memory, so we can bypass runtime // checks to get our current layout. unsafe { - let align = mem::align_of::<T>(); - let size = mem::size_of::<T>() * self.cap; - let layout = Layout::from_size_align_unchecked(size, align); + let layout = Layout::array::<T>(self.cap).unwrap_unchecked(); Some((self.ptr.cast().into(), layout)) } } @@ -475,10 +474,11 @@ impl<T, A: Allocator> RawVec<T, A> { 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 new_size = cap * mem::size_of::<T>();
let ptr = unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + // `Layout::array` cannot overflow here because it would have + // overflowed earlier when capacity was larger. + let new_layout = Layout::array::<T>(cap).unwrap_unchecked(); self.alloc .shrink(ptr, layout, new_layout) .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? diff --git a/rust/alloc/slice.rs b/rust/alloc/slice.rs index 8cb5170f639d..d53f6051f3a8 100644 --- a/rust/alloc/slice.rs +++ b/rust/alloc/slice.rs @@ -50,7 +50,7 @@ //! ``` //! let numbers = &[0, 1, 2]; //! for n in numbers { -//! println!("{} is a number!", n); +//! println!("{n} is a number!"); //! } //! ``` //! @@ -155,7 +155,7 @@ pub use hack::to_vec; // functions are actually methods that are in `impl [T]` but not in // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test -mod hack { +pub(crate) mod hack { use core::alloc::Allocator;
use crate::boxed::Box; @@ -287,7 +287,6 @@ mod hack { } }
-#[lang = "slice_alloc"] #[cfg(not(test))] impl<T> [T] { /// Sorts the slice. @@ -317,6 +316,7 @@ impl<T> [T] { /// assert!(v == [-5, -3, 1, 2, 4]); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sort(&mut self) @@ -372,6 +372,7 @@ impl<T> [T] { /// assert!(v == [5, 4, 3, 2, 1]); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sort_by<F>(&mut self, mut compare: F) @@ -413,6 +414,7 @@ impl<T> [T] { /// assert!(v == [1, 2, -3, 4, -5]); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[stable(feature = "slice_sort_by_key", since = "1.7.0")] #[inline] pub fn sort_by_key<K, F>(&mut self, mut f: F) @@ -459,6 +461,7 @@ impl<T> [T] { /// /// [pdqsort]: https://github.com/orlp/pdqsort #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")] #[inline] pub fn sort_by_cached_key<K, F>(&mut self, f: F) @@ -517,6 +520,7 @@ impl<T> [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[rustc_conversion_suggestion] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -536,6 +540,7 @@ impl<T> [T] { /// let x = s.try_to_vec().unwrap(); /// // Here, `s` and `x` can be modified independently. /// ``` + #[rustc_allow_incoherent_impl] #[inline] #[stable(feature = "kernel", since = "1.0.0")] pub fn try_to_vec(&self) -> Result<Vec<T>, TryReserveError> @@ -559,6 +564,7 @@ impl<T> [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A> @@ -582,6 +588,7 @@ impl<T> [T] { /// let x = s.try_to_vec_in(System).unwrap(); /// // Here, `s` and `x` can be modified independently. /// ``` + #[rustc_allow_incoherent_impl] #[inline] #[stable(feature = "kernel", since = "1.0.0")] pub fn try_to_vec_in<A: Allocator>(&self, alloc: A) -> Result<Vec<T, A>, TryReserveError> @@ -606,6 +613,7 @@ impl<T> [T] { /// /// assert_eq!(x, vec![10, 40, 30]); /// ``` + #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> { @@ -633,6 +641,7 @@ impl<T> [T] { /// // this will panic at runtime /// b"0123456789abcdef".repeat(usize::MAX); /// ``` + #[rustc_allow_incoherent_impl] #[cfg(not(no_global_oom_handling))] #[stable(feature = "repeat_generic_slice", since = "1.40.0")] pub fn repeat(&self, n: usize) -> Vec<T> @@ -701,6 +710,7 @@ impl<T> [T] { /// assert_eq!(["hello", "world"].concat(), "helloworld"); /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); /// ``` + #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output where @@ -719,6 +729,7 @@ impl<T> [T] { /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); /// assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]); /// ``` + #[rustc_allow_incoherent_impl] #[stable(feature = "rename_connect_to_join", since = "1.3.0")] pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output where @@ -737,8 +748,9 @@ impl<T> [T] { /// assert_eq!(["hello", "world"].connect(" "), "hello world"); /// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]); /// ``` + #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] + #[deprecated(since = "1.3.0", note = "renamed to join")] pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output where Self: Join<Separator>, @@ -747,7 +759,6 @@ impl<T> [T] { } }
-#[lang = "slice_u8_alloc"] #[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte @@ -760,6 +771,7 @@ impl [u8] { /// /// [`make_ascii_uppercase`]: slice::make_ascii_uppercase #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the uppercase bytes as a new Vec, \ without modifying the original"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] @@ -780,6 +792,7 @@ impl [u8] { /// /// [`make_ascii_lowercase`]: slice::make_ascii_lowercase #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the lowercase bytes as a new Vec, \ without modifying the original"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] @@ -1134,9 +1147,9 @@ where
impl<T> Drop for MergeHole<T> { fn drop(&mut self) { - // `T` is not a zero-sized type, so it's okay to divide by its size. - let len = (self.end as usize - self.start as usize) / mem::size_of::<T>(); + // `T` is not a zero-sized type, and these are pointers into a slice's elements. unsafe { + let len = self.end.sub_ptr(self.start); ptr::copy_nonoverlapping(self.start, self.dest, len); } } diff --git a/rust/alloc/str.rs b/rust/alloc/str.rs index a1370c2d674c..4e3aec690fdb 100644 --- a/rust/alloc/str.rs +++ b/rust/alloc/str.rs @@ -238,7 +238,6 @@ impl ToOwned for str { }
/// Methods for string slices. -#[lang = "str_alloc"] #[cfg(not(test))] impl str { /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating. @@ -253,6 +252,7 @@ impl str { /// let boxed_bytes = boxed_str.into_boxed_bytes(); /// assert_eq!(*boxed_bytes, *s.as_bytes()); /// ``` + #[rustc_allow_incoherent_impl] #[stable(feature = "str_box_extras", since = "1.20.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] @@ -283,6 +283,7 @@ impl str { /// assert_eq!(s, s.replace("cookie monster", "little lamb")); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] @@ -323,6 +324,7 @@ impl str { /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] @@ -379,6 +381,7 @@ impl str { /// assert_eq!(new_year, new_year.to_lowercase()); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the lowercase string as a new String, \ without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] @@ -461,6 +464,7 @@ impl str { /// assert_eq!("TSCHΓSS", s.to_uppercase()); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "this returns the uppercase string as a new String, \ without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] @@ -496,6 +500,7 @@ impl str { /// assert_eq!(boxed_str.into_string(), string); /// ``` #[stable(feature = "box_str", since = "1.4.0")] + #[rustc_allow_incoherent_impl] #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub fn into_string(self: Box<str>) -> String { @@ -524,6 +529,7 @@ impl str { /// let huge = "0123456789abcdef".repeat(usize::MAX); /// ``` #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use] #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { @@ -552,6 +558,7 @@ impl str { /// [`make_ascii_uppercase`]: str::make_ascii_uppercase /// [`to_uppercase`]: #method.to_uppercase #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] @@ -584,6 +591,7 @@ impl str { /// [`make_ascii_lowercase`]: str::make_ascii_lowercase /// [`to_lowercase`]: #method.to_lowercase #[cfg(not(no_global_oom_handling))] + #[rustc_allow_incoherent_impl] #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] @@ -604,6 +612,7 @@ impl str { /// let s: &str = "a"; /// let ss: String = s.try_to_owned().unwrap(); /// ``` + #[rustc_allow_incoherent_impl] #[inline] #[stable(feature = "kernel", since = "1.0.0")] pub fn try_to_owned(&self) -> Result<String, TryReserveError> { diff --git a/rust/alloc/string.rs b/rust/alloc/string.rs index 5b9780cfc11f..2ba7f30a7503 100644 --- a/rust/alloc/string.rs +++ b/rust/alloc/string.rs @@ -119,27 +119,99 @@ use crate::vec::Vec; /// /// # UTF-8 /// -/// `String`s are always valid UTF-8. This has a few implications, the first of -/// which is that if you need a non-UTF-8 string, consider [`OsString`]. It is -/// similar, but without the UTF-8 constraint. The second implication is that -/// you cannot index into a `String`: +/// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider +/// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8 +/// is a variable width encoding, `String`s are typically smaller than an array of +/// the same `chars`: +/// +/// ``` +/// use std::mem; +/// +/// // `s` is ASCII which represents each `char` as one byte +/// let s = "hello"; +/// assert_eq!(s.len(), 5); +/// +/// // A `char` array with the same contents would be longer because +/// // every `char` is four bytes +/// let s = ['h', 'e', 'l', 'l', 'o']; +/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum(); +/// assert_eq!(size, 20); +/// +/// // However, for non-ASCII strings, the difference will be smaller +/// // and sometimes they are the same +/// let s = "πππππ"; +/// assert_eq!(s.len(), 20); +/// +/// let s = ['π', 'π', 'π', 'π', 'π']; +/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum(); +/// assert_eq!(size, 20); +/// ``` +/// +/// This raises interesting questions as to how `s[i]` should work. +/// What should `i` be here? Several options include byte indices and +/// `char` indices but, because of UTF-8 encoding, only byte indices +/// would provide constant time indexing. Getting the `i`th `char`, for +/// example, is available using [`chars`]: +/// +/// ``` +/// let s = "hello"; +/// let third_character = s.chars().nth(2); +/// assert_eq!(third_character, Some('l')); +/// +/// let s = "πππππ"; +/// let third_character = s.chars().nth(2); +/// assert_eq!(third_character, Some('π')); +/// ``` +/// +/// Next, what should `s[i]` return? Because indexing returns a reference +/// to underlying data it could be `&u8`, `&[u8]`, or something else similar. +/// Since we're only providing one index, `&u8` makes the most sense but that +/// might not be what the user expects and can be explicitly achieved with +/// [`as_bytes()`]: +/// +/// ``` +/// // The first byte is 104 - the byte value of `'h'` +/// let s = "hello"; +/// assert_eq!(s.as_bytes()[0], 104); +/// // or +/// assert_eq!(s.as_bytes()[0], b'h'); +/// +/// // The first byte is 240 which isn't obviously useful +/// let s = "πππππ"; +/// assert_eq!(s.as_bytes()[0], 240); +/// ``` +/// +/// Due to these ambiguities/restrictions, indexing with a `usize` is simply +/// forbidden: /// /// ```compile_fail,E0277 /// let s = "hello"; /// -/// println!("The first letter of s is {}", s[0]); // ERROR!!! +/// // The following will not compile! +/// println!("The first letter of s is {}", s[0]); /// ``` /// +/// It is more clear, however, how `&s[i..j]` should work (that is, +/// indexing with a range). It should accept byte indices (to be constant-time) +/// and return a `&str` which is UTF-8 encoded. This is also called "string slicing". +/// Note this will panic if the byte indices provided are not character +/// boundaries - see [`is_char_boundary`] for more details. See the implementations +/// for [`SliceIndex<str>`] for more details on string slicing. For a non-panicking +/// version of string slicing, see [`get`]. +/// /// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString" +/// [`SliceIndex<str>`]: core::slice::SliceIndex +/// [`as_bytes()`]: str::as_bytes +/// [`get`]: str::get +/// [`is_char_boundary`]: str::is_char_boundary /// -/// Indexing is intended to be a constant-time operation, but UTF-8 encoding -/// does not allow us to do this. Furthermore, it's not clear what sort of -/// thing the index should return: a byte, a codepoint, or a grapheme cluster. -/// The [`bytes`] and [`chars`] methods return iterators over the first -/// two, respectively. +/// The [`bytes`] and [`chars`] methods return iterators over the bytes and +/// codepoints of the string, respectively. To iterate over codepoints along +/// with byte indices, use [`char_indices`]. /// /// [`bytes`]: str::bytes /// [`chars`]: str::chars +/// [`char_indices`]: str::char_indices /// /// # Deref /// @@ -700,7 +772,10 @@ impl String { /// * The first `length` bytes at `buf` need to be valid UTF-8. /// /// Violating these may cause problems like corrupting the allocator's - /// internal data structures. + /// internal data structures. For example, it is normally **not** safe to + /// build a `String` from a pointer to a C `char` array containing UTF-8 + /// _unless_ you are certain that array was originally allocated by the + /// Rust standard library's allocator. /// /// The ownership of `buf` is effectively transferred to the /// `String` which may then deallocate, reallocate or change the @@ -1040,7 +1115,7 @@ impl String { }
/// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `String`. After calling `reserve_exact`, + /// be inserted in the given `String`. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -2720,7 +2795,7 @@ impl From<String> for Vec<u8> { /// let v1 = Vec::from(s1); /// /// for b in v1 { - /// println!("{}", b); + /// println!("{b}"); /// } /// ``` fn from(string: String) -> Vec<u8> { diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs index 80ca4c0dcd24..e57011b7c3da 100644 --- a/rust/compiler_builtins.rs +++ b/rust/compiler_builtins.rs @@ -36,6 +36,18 @@ macro_rules! define_panicking_intrinsics( } );
+define_panicking_intrinsics!("`f32` should not be used", { + __eqsf2, + __gesf2, + __lesf2, + __nesf2, + __unordsf2, +}); + +define_panicking_intrinsics!("`f64` should not be used", { + __unorddf2, +}); + define_panicking_intrinsics!("`i128` should not be used", { __ashrti3, __muloti4, @@ -50,8 +62,18 @@ define_panicking_intrinsics!("`u128` should not be used", { __umodti3, });
+#[cfg(target_arch = "arm")] +define_panicking_intrinsics!("`f32` should not be used", { + __aeabi_fcmpeq, + __aeabi_fcmpun, +}); + +#[cfg(target_arch = "arm")] +define_panicking_intrinsics!("`f64` should not be used", { + __aeabi_dcmpun, +}); + #[cfg(target_arch = "arm")] define_panicking_intrinsics!("`u64` division/modulo should not be used", { __aeabi_uldivmod, - __mulodi4, }); diff --git a/rust/helpers.c b/rust/helpers.c index eb7a66c77cb2..ead3a64f700c 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -504,13 +504,13 @@ EXPORT_SYMBOL_GPL(rust_helper_read_seqcount_retry);
void rust_helper_write_seqcount_begin(seqcount_t *s) { - do_write_seqcount_begin(s); + //do_write_seqcount_begin(s); } EXPORT_SYMBOL_GPL(rust_helper_write_seqcount_begin);
void rust_helper_write_seqcount_end(seqcount_t *s) { - do_write_seqcount_end(s); + //do_write_seqcount_end(s); } EXPORT_SYMBOL_GPL(rust_helper_write_seqcount_end);
diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs index 7ca5358d2580..61eedcd21ca4 100644 --- a/rust/kernel/amba.rs +++ b/rust/kernel/amba.rs @@ -63,7 +63,7 @@ pub trait Driver { /// Cleans any resources up that are associated with the device. /// /// This is called when the driver is detached from the device. - fn remove(_data: &Self::Data) {} + fn remove(_data: &Self::Data) -> i32; }
/// An adapter for the registration of Amba drivers. @@ -133,7 +133,7 @@ unsafe extern "C" fn probe_callback<T: Driver>( } }
-unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) { +unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) -> i32 { // SAFETY: `adev` is valid by the contract with the C code. let ptr = unsafe { bindings::amba_get_drvdata(adev) }; // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to @@ -142,6 +142,7 @@ unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device let data = unsafe { T::Data::from_pointer(ptr) }; T::remove(&data); <T::Data as driver::DeviceRemoval>::device_remove(&data); + 0 }
/// An Amba device. diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 236d278f5576..a499a95c1ffd 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -148,7 +148,7 @@ pub unsafe trait RawDevice { // `fmt::Arguments`, which is what we're passing as the last argument. #[cfg(CONFIG_PRINTK)] unsafe { - bindings::_dev_printk( + bindings::dev_printk( klevel as *const _ as *const c_types::c_char, self.raw_device(), c_str!("%pA").as_char_ptr(), diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index e1b3b324bb3d..064da85cdc5e 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -539,6 +539,10 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> { } else { None }, + kabi_reserved1: 0, + kabi_reserved2: 0, + kabi_reserved3: 0, + kabi_reserved4: 0, };
/// Builds an instance of [`struct file_operations`]. diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs index b1d067de6925..f351e39528b1 100644 --- a/rust/kernel/irq.rs +++ b/rust/kernel/irq.rs @@ -375,7 +375,7 @@ impl Domain { /// `ChainedGuard` instance. pub fn generic_handle_chained(&self, hwirq: u32, _guard: &ChainedGuard<'_>) { // SAFETY: `ptr` is valid by the type invariants. - unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) }; + //unsafe { bindings::generic_handle_domain_irq(self.ptr, hwirq) }; } }
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs index 0495ab778144..be766acca7d9 100644 --- a/rust/kernel/net.rs +++ b/rust/kernel/net.rs @@ -108,9 +108,8 @@ unsafe impl AlwaysRefCounted for SkBuff { unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) { // SAFETY: The safety requirements guarantee that the refcount is nonzero. unsafe { - bindings::kfree_skb_reason( - obj.cast().as_ptr(), - bindings::skb_drop_reason_SKB_DROP_REASON_NOT_SPECIFIED, + bindings::__kfree_skb( + obj.cast().as_ptr() ) }; } diff --git a/rust/kernel/net/filter.rs b/rust/kernel/net/filter.rs index 3241100a1561..26e4cf811294 100644 --- a/rust/kernel/net/filter.rs +++ b/rust/kernel/net/filter.rs @@ -205,7 +205,7 @@ impl<T: Filter> Registration<T> { this.hook.priority = pri_base.saturating_add(priority); this.hook.priv_ = data_pointer as _; this.hook.hook = Some(Self::hook_callback); - crate::static_assert!(bindings::nf_hook_ops_type_NF_HOOK_OP_UNDEFINED == 0); + // crate::static_assert!(bindings::nf_hook_ops_type_NF_HOOK_OP_UNDEFINED == 0);
if let Some(ref device) = dev { this.hook.dev = device.0.get(); @@ -276,13 +276,13 @@ pub mod netdev { use crate::bindings;
/// Hooks allowed in the [`super::Family::NetDev`] family. - #[repr(u32)] + //#[repr(u32)] pub enum Hook { - /// All inbound packets through the given device. - Ingress = bindings::nf_dev_hooks_NF_NETDEV_INGRESS, + // /// All inbound packets through the given device. + // Ingress = bindings::nf_dev_hooks_NF_NETDEV_INGRESS,
- /// All outbound packets through the given device. - Egress = bindings::nf_dev_hooks_NF_NETDEV_EGRESS, + // /// All outbound packets through the given device. + // Egress = bindings::nf_dev_hooks_NF_NETDEV_EGRESS, } }
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 9846bd13eab6..323bb3ec83e8 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -104,7 +104,7 @@ pub unsafe fn call_printk( // `_printk` does not seem to fail in any path. #[cfg(CONFIG_PRINTK)] unsafe { - bindings::_printk( + bindings::printk( format_string.as_ptr() as _, module_name.as_ptr(), &args as *const _ as *const c_void, @@ -125,7 +125,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) { // SAFETY: The format string is fixed. #[cfg(CONFIG_PRINTK)] unsafe { - bindings::_printk( + bindings::printk( format_strings::CONT.as_ptr() as _, &args as *const _ as *const c_void, ); diff --git a/rust/kernel/random.rs b/rust/kernel/random.rs index a0926cb68a75..812bf8944ece 100644 --- a/rust/kernel/random.rs +++ b/rust/kernel/random.rs @@ -17,7 +17,7 @@ pub fn getrandom(dest: &mut [u8]) -> Result { }
unsafe { - bindings::get_random_bytes(dest.as_mut_ptr() as *mut c_types::c_void, dest.len()); + bindings::get_random_bytes(dest.as_mut_ptr() as *mut c_types::c_void, dest.len() as i32); } Ok(()) } @@ -37,6 +37,6 @@ pub fn getrandom_nonblock(dest: &mut [u8]) -> Result { /// Does *not* credit the kernel entropy counter though. pub fn add_randomness(data: &[u8]) { unsafe { - bindings::add_device_randomness(data.as_ptr() as *const c_types::c_void, data.len()); + bindings::add_device_randomness(data.as_ptr() as *const c_types::c_void, data.len() as u32); } } diff --git a/samples/rust/Makefile b/samples/rust/Makefile index fb5a205ebb8c..c1a401cf94f1 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -11,6 +11,5 @@ obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE) += rust_semaphore.o obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C) += rust_semaphore_c.o obj-$(CONFIG_SAMPLE_RUST_RANDOM) += rust_random.o obj-$(CONFIG_SAMPLE_RUST_PLATFORM) += rust_platform.o -obj-$(CONFIG_SAMPLE_RUST_NETFILTER) += rust_netfilter.o
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh new file mode 100755 index 000000000000..2401c86fcf53 --- /dev/null +++ b/scripts/cc-version.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Print the C compiler name and its version in a 5 or 6-digit form. +# Also, perform the minimum version check. + +set -e + +# Print the C compiler name and some version components. +get_c_compiler_info() +{ + cat <<- EOF | "$@" -E -P -x c - 2>/dev/null + #if defined(__clang__) + Clang __clang_major__ __clang_minor__ __clang_patchlevel__ + #elif defined(__INTEL_COMPILER) + ICC __INTEL_COMPILER __INTEL_COMPILER_UPDATE + #elif defined(__GNUC__) + GCC __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ + #else + unknown + #endif + EOF +} + +# Convert the version string x.y.z to a canonical 5 or 6-digit form. +get_canonical_version() +{ + IFS=. + set -- $1 + echo $((10000 * $1 + 100 * $2 + $3)) +} + +# $@ instead of $1 because multiple words might be given, e.g. CC="ccache gcc". +orig_args="$@" +set -- $(get_c_compiler_info "$@") + +name=$1 + +min_tool_version=$(dirname $0)/min-tool-version.sh + +case "$name" in +GCC) + version=$2.$3.$4 + min_version=$($min_tool_version gcc) + ;; +Clang) + version=$2.$3.$4 + min_version=$($min_tool_version llvm) + ;; +ICC) + version=$(($2 / 100)).$(($2 % 100)).$3 + min_version=$($min_tool_version icc) + ;; +*) + echo "$orig_args: unknown C compiler" >&2 + exit 1 + ;; +esac + +cversion=$(get_canonical_version $version) +min_cversion=$(get_canonical_version $min_version) + +if [ "$cversion" -lt "$min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** C compiler is too old." + echo >&2 "*** Your $name version: $version" + echo >&2 "*** Minimum $name version: $min_version" + echo >&2 "***" + exit 1 +fi + +echo $name $cversion diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 867b06c6d279..2e5c5011ed47 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -1043,13 +1043,162 @@ static int conf_touch_deps(void) return 0; }
+/* The returned pointer must be freed on the caller side */ +static char *escape_string_value(const char *in) +{ + const char *p; + char *out; + size_t len; + + len = strlen(in) + strlen("""") + 1; + + p = in; + while (1) { + p += strcspn(p, ""\"); + + if (p[0] == '\0') + break; + + len++; + p++; + } + + out = xmalloc(len); + out[0] = '\0'; + + strcat(out, """); + + p = in; + while (1) { + len = strcspn(p, ""\"); + strncat(out, p, len); + p += len; + + if (p[0] == '\0') + break; + + strcat(out, "\"); + strncat(out, p++, 1); + } + + strcat(out, """); + + return out; +} + +static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) +{ + const char *val; + const char *val_prefix = ""; + char *val_prefixed = NULL; + size_t val_prefixed_len; + char *escaped = NULL; + + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + /* + * We do not care about disabled ones, i.e. no need for + * what otherwise are "comments" in other printers. + */ + if (*val == 'n') + return; + + /* + * To have similar functionality to the C macro `IS_ENABLED()` + * we provide an empty `--cfg CONFIG_X` here in both `y` + * and `m` cases. + * + * Then, the common `fprintf()` below will also give us + * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can + * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. + */ + fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); + break; + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; + break; + default: + break; + } + + if (strlen(val_prefix) > 0) { + val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; + val_prefixed = xmalloc(val_prefixed_len); + snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); + val = val_prefixed; + } + + /* All values get escaped: the `--cfg` option only takes strings */ + escaped = escape_string_value(val); + val = escaped; + + fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); + + free(escaped); + free(val_prefixed); +} + +static int __conf_write_autoconf(const char *filename, + void (*print_symbol)(FILE *, struct symbol *), + const struct comment_style *comment_style) +{ + char tmp[PATH_MAX]; + FILE *file; + struct symbol *sym; + int ret, i; + + if (make_parent_dir(filename)) + return -1; + + ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename); + if (ret >= sizeof(tmp)) /* check truncation */ + return -1; + + file = fopen(tmp, "w"); + if (!file) { + perror("fopen"); + return -1; + } + + for_all_symbols(i, sym) + if ((sym->flags & SYMBOL_WRITE) && sym->name) + print_symbol(file, sym); + + /* check possible errors in conf_write_heading() and print_symbol() */ + if (ferror(file)) + return -1; + + fclose(file); + + if (rename(tmp, filename)) { + perror("rename"); + return -1; + } + + return 0; +} + +static const char *conf_get_rustccfg_name(void) +{ + char *name = getenv("KCONFIG_RUSTCCFG"); + + return name ? name : "include/generated/rustc_cfg"; +} + int conf_write_autoconf(int overwrite) { struct symbol *sym; const char *name; const char *autoconf_name = conf_get_autoconfig_name(); FILE *out, *out_h; - int i; + int ret, i;
if (!overwrite && is_present(autoconf_name)) return 0; @@ -1101,7 +1250,10 @@ int conf_write_autoconf(int overwrite) if (rename(".tmpconfig", autoconf_name)) return 1;
- return 0; + ret = __conf_write_autoconf(conf_get_rustccfg_name(), + print_symbol_for_rustccfg, + NULL); + return ret; }
static int sym_change_count; diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh new file mode 100755 index 000000000000..b6593eac5003 --- /dev/null +++ b/scripts/min-tool-version.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Print the minimum supported version of the given tool. +# When you raise the minimum version, please update +# Documentation/process/changes.rst as well. + +set -e + +if [ $# != 1 ]; then + echo "Usage: $0 toolname" >&2 + exit 1 +fi + +case "$1" in +binutils) + echo 2.23.0 + ;; +gcc) + echo 5.1.0 + ;; +icc) + # temporary + echo 16.0.3 + ;; +llvm) + if [ "$SRCARCH" = s390 ]; then + echo 14.0.0 + else + echo 11.0.0 + fi + ;; +rustc) + echo 1.62.0 + ;; +bindgen) + echo 0.56.0 + ;; +*) + echo "$1: unknown tool" >&2 + exit 1 + ;; +esac