From d6a1b36cb41539be32498d1188eb9d70cd4249fb Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 14 Mar 2024 16:01:29 +0300 Subject: [PATCH 1/6] Implement ptr_as_ref_unchecked (#122034) --- library/core/src/ptr/const_ptr.rs | 48 ++++++++++++++ library/core/src/ptr/mut_ptr.rs | 103 ++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a0c04d3f65dfd..a8af4c1b29138 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -362,6 +362,54 @@ impl *const T { if self.is_null() { None } else { unsafe { Some(&*self) } } } + /// Returns a shared reference to the value behind the pointer. + /// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead. + /// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead. + /// + /// [`as_ref`]: #method.as_ref + /// [`as_uninit_ref`]: #method.as_uninit_ref + /// + /// # Safety + /// + /// When calling this method, you have to ensure that all of the following is true: + /// + /// * The pointer must be properly aligned. + /// + /// * It must be "dereferenceable" in the sense defined in [the module documentation]. + /// + /// * The pointer must point to an initialized instance of `T`. + /// + /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is + /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. + /// In particular, while this reference exists, the memory the pointer points to must + /// not get mutated (except inside `UnsafeCell`). + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// [the module documentation]: crate::ptr#safety + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_as_ref_unchecked)] + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// println!("We got back the value: {}!", ptr.as_ref_unchecked()); + /// } + /// ``` + // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. + #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] + #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[inline] + #[must_use] + pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { + // SAFETY: the caller must guarantee that `self` is valid for a reference + unsafe { &*self } + } + /// Returns `None` if the pointer is null, or else returns a shared reference to /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require /// that the value has to be initialized. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6a9033a144deb..4a6c9e8b8e0e3 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -372,6 +372,57 @@ impl *mut T { if self.is_null() { None } else { unsafe { Some(&*self) } } } + /// Returns a shared reference to the value behind the pointer. + /// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead. + /// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead. + /// + /// For the mutable counterpart see [`as_mut_unchecked`]. + /// + /// [`as_ref`]: #method.as_ref + /// [`as_uninit_ref`]: #method.as_uninit_ref + /// [`as_mut_unchecked`]: #method.as_mut_unchecked + /// + /// # Safety + /// + /// When calling this method, you have to ensure that all of the following is true: + /// + /// * The pointer must be properly aligned. + /// + /// * It must be "dereferenceable" in the sense defined in [the module documentation]. + /// + /// * The pointer must point to an initialized instance of `T`. + /// + /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is + /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. + /// In particular, while this reference exists, the memory the pointer points to must + /// not get mutated (except inside `UnsafeCell`). + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// [the module documentation]: crate::ptr#safety + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_as_ref_unchecked)] + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// println!("We got back the value: {}!", ptr.as_ref_unchecked()); + /// } + /// ``` + // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized. + #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] + #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[inline] + #[must_use] + pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T { + // SAFETY: the caller must guarantee that `self` is valid for a reference + unsafe { &*self } + } + /// Returns `None` if the pointer is null, or else returns a shared reference to /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require /// that the value has to be initialized. @@ -693,6 +744,58 @@ impl *mut T { if self.is_null() { None } else { unsafe { Some(&mut *self) } } } + /// Returns a unique reference to the value behind the pointer. + /// If the pointer may be null or the value may be uninitialized, [`as_uninit_mut`] must be used instead. + /// If the pointer may be null, but the value is known to have been initialized, [`as_mut`] must be used instead. + /// + /// For the shared counterpart see [`as_ref_unchecked`]. + /// + /// [`as_mut`]: #method.as_mut + /// [`as_uninit_mut`]: #method.as_uninit_mut + /// [`as_ref_unchecked`]: #method.as_mut_unchecked + /// + /// # Safety + /// + /// When calling this method, you have to ensure that all of the following is true: + /// + /// * The pointer must be properly aligned. + /// + /// * It must be "dereferenceable" in the sense defined in [the module documentation]. + /// + /// * The pointer must point to an initialized instance of `T`. + /// + /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is + /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. + /// In particular, while this reference exists, the memory the pointer points to must + /// not get mutated (except inside `UnsafeCell`). + /// + /// This applies even if the result of this method is unused! + /// (The part about being initialized is not yet fully decided, but until + /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// + /// [the module documentation]: crate::ptr#safety + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_as_ref_unchecked)] + /// let mut s = [1, 2, 3]; + /// let ptr: *mut u32 = s.as_mut_ptr(); + /// let first_value = unsafe { ptr.as_mut_unchecked() }; + /// *first_value = 4; + /// # assert_eq!(s, [4, 2, 3]); + /// println!("{s:?}"); // It'll print: "[4, 2, 3]". + /// ``` + // FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized. + #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")] + #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[inline] + #[must_use] + pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T { + // SAFETY: the caller must guarantee that `self` is valid for a reference + unsafe { &mut *self } + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. In contrast to [`as_mut`], this does not require /// that the value has to be initialized. From 3ad0618076af29d23c8d0ca386e4da0b1f271d18 Mon Sep 17 00:00:00 2001 From: Jacob Trueb Date: Thu, 11 Apr 2024 13:24:32 -0500 Subject: [PATCH 2/6] Fix cannot usage in time.rs --- library/core/src/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 78494b866b108..72f6a3b773bb5 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1437,10 +1437,10 @@ impl TryFromFloatSecsError { const fn description(&self) -> &'static str { match self.kind { TryFromFloatSecsErrorKind::Negative => { - "can not convert float seconds to Duration: value is negative" + "cannot convert float seconds to Duration: value is negative" } TryFromFloatSecsErrorKind::OverflowOrNan => { - "can not convert float seconds to Duration: value is either too big or NaN" + "cannot convert float seconds to Duration: value is either too big or NaN" } } } From 589c2fe24d1f9e7bde8a50b07bb53eb4fbee6d8e Mon Sep 17 00:00:00 2001 From: Lin Yihai Date: Mon, 29 Apr 2024 14:59:39 +0800 Subject: [PATCH 3/6] Add raw identifier in a typo suggestion --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- tests/ui/span/suggestion-raw-68962.rs | 11 +++++++++++ tests/ui/span/suggestion-raw-68962.stderr | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/span/suggestion-raw-68962.rs create mode 100644 tests/ui/span/suggestion-raw-68962.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 12484462f82f4..01e279b6d04fa 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1617,7 +1617,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let post = format!(", consider renaming `{}` into `{snippet}`", suggestion.candidate); (span, snippet, post) } else { - (span, suggestion.candidate.to_string(), String::new()) + (span, suggestion.candidate.to_ident_string(), String::new()) }; let msg = match suggestion.target { SuggestionTarget::SimilarlyNamed => format!( diff --git a/tests/ui/span/suggestion-raw-68962.rs b/tests/ui/span/suggestion-raw-68962.rs new file mode 100644 index 0000000000000..0b581308f6628 --- /dev/null +++ b/tests/ui/span/suggestion-raw-68962.rs @@ -0,0 +1,11 @@ +fn r#fn() {} + +fn main() { + let r#final = 1; + + // Should correctly suggest variable defined using raw identifier. + fina; //~ ERROR cannot find value + + // Should correctly suggest function defined using raw identifier. + f(); //~ ERROR cannot find function +} diff --git a/tests/ui/span/suggestion-raw-68962.stderr b/tests/ui/span/suggestion-raw-68962.stderr new file mode 100644 index 0000000000000..2e25f5cbdf58d --- /dev/null +++ b/tests/ui/span/suggestion-raw-68962.stderr @@ -0,0 +1,18 @@ +error[E0425]: cannot find value `fina` in this scope + --> $DIR/suggestion-raw-68962.rs:7:5 + | +LL | fina; + | ^^^^ help: a local variable with a similar name exists: `r#final` + +error[E0425]: cannot find function `f` in this scope + --> $DIR/suggestion-raw-68962.rs:10:5 + | +LL | fn r#fn() {} + | --------- similarly named function `r#fn` defined here +... +LL | f(); + | ^ help: a function with a similar name exists: `r#fn` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. From e610a52a6259cae4c9f3ebdb6016e68b507878e4 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Wed, 1 May 2024 19:28:45 +0100 Subject: [PATCH 4/6] Describe and use CStr literals in CStr and CString docs --- library/alloc/src/ffi/c_str.rs | 14 +++++--------- library/core/src/ffi/c_str.rs | 35 ++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 6a64eaf576bb9..f143e5578717f 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -41,6 +41,7 @@ use crate::sync::Arc; /// or anything that implements [Into]<[Vec]<[u8]>> (for /// example, you can build a `CString` straight out of a [`String`] or /// a &[str], since both implement that trait). +/// You can create a `CString` from a literal with `CString::from(c"Text")`. /// /// The [`CString::new`] method will actually check that the provided &[[u8]] /// does not have 0 bytes in the middle, and return an error if it @@ -1069,27 +1070,22 @@ impl CStr { /// /// # Examples /// - /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8: + /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8. The leading + /// `c` on the string literal denotes a `CStr`. /// /// ``` /// use std::borrow::Cow; - /// use std::ffi::CStr; /// - /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0") - /// .expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World")); + /// assert_eq!(c"Hello World".to_string_lossy(), Cow::Borrowed("Hello World")); /// ``` /// /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: /// /// ``` /// use std::borrow::Cow; - /// use std::ffi::CStr; /// - /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") - /// .expect("CStr::from_bytes_with_nul failed"); /// assert_eq!( - /// cstr.to_string_lossy(), + /// c"Hello \xF0\x90\x80World".to_string_lossy(), /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index f4f33f8584bd0..9d914d798eb22 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -23,28 +23,32 @@ use crate::str; /// /// This type represents a borrowed reference to a nul-terminated /// array of bytes. It can be constructed safely from a &[[u8]] -/// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust &[str] by performing UTF-8 validation, or -/// into an owned `CString`. +/// slice, or unsafely from a raw `*const c_char`. It can be expressed as a +/// literal in the form `c"Hello world"`. +/// +/// The `CStr` can then be converted to a Rust &[str] by performing +/// UTF-8 validation, or into an owned `CString`. /// /// `&CStr` is to `CString` as &[str] is to `String`: the former /// in each pair are borrowed references; the latter are owned /// strings. /// /// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)` -/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions. -/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor -/// to provide a safe interface to other consumers. +/// notwithstanding) and should not be placed in the signatures of FFI functions. +/// Instead, safe wrappers of FFI functions may leverage [`CStr::as_ptr`] and the unsafe +/// [`CStr::from_ptr`] constructor to provide a safe interface to other consumers. /// /// # Examples /// /// Inspecting a foreign C string: /// -/// ```ignore (extern-declaration) +/// ``` /// use std::ffi::CStr; /// use std::os::raw::c_char; /// +/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn my_string() -> *const c_char; } +/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } /// /// unsafe { /// let slice = CStr::from_ptr(my_string()); @@ -54,12 +58,14 @@ use crate::str; /// /// Passing a Rust-originating C string: /// -/// ```ignore (extern-declaration) +/// ``` /// use std::ffi::{CString, CStr}; /// use std::os::raw::c_char; /// /// fn work(data: &CStr) { +/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn work_with(data: *const c_char); } +/// # unsafe extern "C" fn work_with(s: *const c_char) {} /// /// unsafe { work_with(data.as_ptr()) } /// } @@ -70,11 +76,13 @@ use crate::str; /// /// Converting a foreign C string into a Rust `String`: /// -/// ```ignore (extern-declaration) +/// ``` /// use std::ffi::CStr; /// use std::os::raw::c_char; /// +/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn my_string() -> *const c_char; } +/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } /// /// fn my_string_safe() -> String { /// let cstr = unsafe { CStr::from_ptr(my_string()) }; @@ -241,11 +249,11 @@ impl CStr { /// /// # Examples /// - /// ```ignore (extern-declaration) + /// ``` /// use std::ffi::{c_char, CStr}; /// - /// extern "C" { - /// fn my_string() -> *const c_char; + /// fn my_string() -> *const c_char { + /// c"hello".as_ptr() /// } /// /// unsafe { @@ -264,6 +272,8 @@ impl CStr { /// BYTES.as_ptr().cast() /// }; /// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) }; + /// + /// assert_eq!(c"Hello, world!", HELLO); /// ``` /// /// [valid]: core::ptr#safety @@ -549,6 +559,7 @@ impl CStr { /// /// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?; /// assert!(empty_cstr.is_empty()); + /// assert!(c"".is_empty()); /// # Ok(()) /// # } /// ``` From 0e0042f16ec74bd9b219f4df65c5589636cacd15 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Thu, 2 May 2024 21:29:13 +0100 Subject: [PATCH 5/6] Update based on review --- library/core/src/ffi/c_str.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 9d914d798eb22..57cc0e4d612b8 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -46,9 +46,9 @@ use crate::str; /// use std::ffi::CStr; /// use std::os::raw::c_char; /// -/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead +/// # /* Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn my_string() -> *const c_char; } -/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } +/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } /// /// unsafe { /// let slice = CStr::from_ptr(my_string()); @@ -63,9 +63,9 @@ use crate::str; /// use std::os::raw::c_char; /// /// fn work(data: &CStr) { -/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead +/// # /* Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn work_with(data: *const c_char); } -/// # unsafe extern "C" fn work_with(s: *const c_char) {} +/// # */ unsafe extern "C" fn work_with(s: *const c_char) {} /// /// unsafe { work_with(data.as_ptr()) } /// } @@ -80,9 +80,9 @@ use crate::str; /// use std::ffi::CStr; /// use std::os::raw::c_char; /// -/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead +/// # /* Extern functions are awkward in doc comments - fake it instead /// extern "C" { fn my_string() -> *const c_char; } -/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } +/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() } /// /// fn my_string_safe() -> String { /// let cstr = unsafe { CStr::from_ptr(my_string()) }; @@ -258,7 +258,7 @@ impl CStr { /// /// unsafe { /// let slice = CStr::from_ptr(my_string()); - /// println!("string returned: {}", slice.to_str().unwrap()); + /// assert_eq!(slice.to_str().unwrap(), "hello"); /// } /// ``` /// From 3f6703bbd8537e4d8957a5cb458b8e53a8e0e9f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2024 10:06:06 +0200 Subject: [PATCH 6/6] default_alloc_error_hook: explain difference to default __rdl_oom in alloc --- library/std/src/alloc.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index dc0e302a81088..b98fbbf762fa2 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -353,6 +353,12 @@ fn default_alloc_error_hook(layout: Layout) { if unsafe { __rust_alloc_error_handler_should_panic != 0 } { panic!("memory allocation of {} bytes failed", layout.size()); } else { + // This is the default path taken on OOM, and the only path taken on stable with std. + // Crucially, it does *not* call any user-defined code, and therefore users do not have to + // worry about allocation failure causing reentrancy issues. That makes it different from + // the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is + // called when there is no `#[alloc_error_handler]`), which triggers a regular panic and + // thus can invoke a user-defined panic hook, executing arbitrary user-defined code. rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); } }