diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /src/doc/nomicon | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc/nomicon')
-rw-r--r-- | src/doc/nomicon/src/phantom-data.md | 35 | ||||
-rw-r--r-- | src/doc/nomicon/src/races.md | 33 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-drain.md | 20 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-final.md | 43 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-insert-remove.md | 5 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-into-iter.md | 22 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-layout.md | 1 | ||||
-rw-r--r-- | src/doc/nomicon/src/vec/vec-raw.md | 32 |
8 files changed, 101 insertions, 90 deletions
diff --git a/src/doc/nomicon/src/phantom-data.md b/src/doc/nomicon/src/phantom-data.md index 449d9e774..cd2428d96 100644 --- a/src/doc/nomicon/src/phantom-data.md +++ b/src/doc/nomicon/src/phantom-data.md @@ -106,7 +106,14 @@ that that `Vec<T>` _owns_ values of type `T` (more precisely: may use values of in its `Drop` implementation), and Rust will thus not allow them to _dangle_ should a `Vec<T>` be dropped. -**Adding an extra `_owns_T: PhantomData<T>` field is thus _superfluous_ and accomplishes nothing**. +When a type already has a `Drop impl`, **adding an extra `_owns_T: PhantomData<T>` field +is thus _superfluous_ and accomplishes nothing**, dropck-wise (it still affects variance +and auto-traits). + + - (advanced edge case: if the type containing the `PhantomData` has no `Drop` impl at all, + but still has drop glue (by having _another_ field with drop glue), then the + dropck/`#[may_dangle]` considerations mentioned herein do apply as well: a `PhantomData<T>` + field will then require `T` to be droppable whenever the containing type goes out of scope). ___ @@ -234,14 +241,18 @@ standard library made a utility for itself called `Unique<T>` which: Here’s a table of all the wonderful ways `PhantomData` could be used: -| Phantom type | `'a` | `T` | `Send` | `Sync` | -|-----------------------------|-----------|-----------------------------|-----------|-----------| -| `PhantomData<T>` | - | covariant (with drop check) | `T: Send` | `T: Sync` | -| `PhantomData<&'a T>` | covariant | covariant | `T: Sync` | `T: Sync` | -| `PhantomData<&'a mut T>` | covariant | invariant | `T: Send` | `T: Sync` | -| `PhantomData<*const T>` | - | covariant | - | - | -| `PhantomData<*mut T>` | - | invariant | - | - | -| `PhantomData<fn(T)>` | - | contravariant | `Send` | `Sync` | -| `PhantomData<fn() -> T>` | - | covariant | `Send` | `Sync` | -| `PhantomData<fn(T) -> T>` | - | invariant | `Send` | `Sync` | -| `PhantomData<Cell<&'a ()>>` | invariant | - | `Send` | - | +| Phantom type | variance of `'a` | variance of `T` | `Send`/`Sync`<br/>(or lack thereof) | dangling `'a` or `T` in drop glue<br/>(_e.g._, `#[may_dangle] Drop`) | +|-----------------------------|:----------------:|:-----------------:|:-----------------------------------------:|:------------------------------------------------:| +| `PhantomData<T>` | - | **cov**ariant | inherited | disallowed ("owns `T`") | +| `PhantomData<&'a T>` | **cov**ariant | **cov**ariant | `Send + Sync`<br/>requires<br/>`T : Sync` | allowed | +| `PhantomData<&'a mut T>` | **cov**ariant | **inv**ariant | inherited | allowed | +| `PhantomData<*const T>` | - | **cov**ariant | `!Send + !Sync` | allowed | +| `PhantomData<*mut T>` | - | **inv**ariant | `!Send + !Sync` | allowed | +| `PhantomData<fn(T)>` | - | **contra**variant | `Send + Sync` | allowed | +| `PhantomData<fn() -> T>` | - | **cov**ariant | `Send + Sync` | allowed | +| `PhantomData<fn(T) -> T>` | - | **inv**ariant | `Send + Sync` | allowed | +| `PhantomData<Cell<&'a ()>>` | **inv**ariant | - | `Send + !Sync` | allowed | + + - Note: opting out of the `Unpin` auto-trait requires the dedicated [`PhantomPinned`] type instead. + +[`PhantomPinned`]: ../core/marker/struct.PhantomPinned.html diff --git a/src/doc/nomicon/src/races.md b/src/doc/nomicon/src/races.md index cb78ac652..d5f1ea0d3 100644 --- a/src/doc/nomicon/src/races.md +++ b/src/doc/nomicon/src/races.md @@ -6,26 +6,28 @@ Safe Rust guarantees an absence of data races, which are defined as: * one or more of them is a write * one or more of them is unsynchronized -A data race has Undefined Behavior, and is therefore impossible to perform -in Safe Rust. Data races are *mostly* prevented through Rust's ownership system: +A data race has Undefined Behavior, and is therefore impossible to perform in +Safe Rust. Data races are *mostly* prevented through Rust's ownership system: it's impossible to alias a mutable reference, so it's impossible to perform a data race. Interior mutability makes this more complicated, which is largely why -we have the Send and Sync traits (see below). +we have the Send and Sync traits (see the next section for more on this). **However Rust does not prevent general race conditions.** -This is pretty fundamentally impossible, and probably honestly undesirable. Your -hardware is racy, your OS is racy, the other programs on your computer are racy, -and the world this all runs in is racy. Any system that could genuinely claim to -prevent *all* race conditions would be pretty awful to use, if not just -incorrect. +This is mathematically impossible in situations where you do not control the +scheduler, which is true for the normal OS environment. If you do control +preemption, it _can be_ possible to prevent general races - this technique is +used by frameworks such as [RTIC](https://github.com/rtic-rs/rtic). However, +actually having control over scheduling is a very uncommon case. -So it's perfectly "fine" for a Safe Rust program to get deadlocked or do -something nonsensical with incorrect synchronization. Obviously such a program -isn't very good, but Rust can only hold your hand so far. Still, a race -condition can't violate memory safety in a Rust program on its own. Only in -conjunction with some other unsafe code can a race condition actually violate -memory safety. For instance: +For this reason, it is considered "safe" for Rust to get deadlocked or do +something nonsensical with incorrect synchronization: this is known as a general +race condition or resource race. Obviously such a program isn't very good, but +Rust of course cannot prevent all logic errors. + +In any case, a race condition cannot violate memory safety in a Rust program on +its own. Only in conjunction with some other unsafe code can a race condition +actually violate memory safety. For instance, a correct program looks like this: ```rust,no_run use std::thread; @@ -58,6 +60,9 @@ thread::spawn(move || { println!("{}", data[idx.load(Ordering::SeqCst)]); ``` +We can cause a data race if we instead do the bound check in advance, and then +unsafely access the data with an unchecked value: + ```rust,no_run use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/doc/nomicon/src/vec/vec-drain.md b/src/doc/nomicon/src/vec/vec-drain.md index 7a0e7f81a..763c82ae6 100644 --- a/src/doc/nomicon/src/vec/vec-drain.md +++ b/src/doc/nomicon/src/vec/vec-drain.md @@ -93,7 +93,7 @@ impl<T> IntoIterator for Vec<T> { mem::forget(self); IntoIter { - iter: iter, + iter, _buf: buf, } } @@ -135,18 +135,16 @@ impl<'a, T> Drop for Drain<'a, T> { impl<T> Vec<T> { pub fn drain(&mut self) -> Drain<T> { - unsafe { - let iter = RawValIter::new(&self); + let iter = unsafe { RawValIter::new(&self) }; - // this is a mem::forget safety thing. If Drain is forgotten, we just - // leak the whole Vec's contents. Also we need to do this *eventually* - // anyway, so why not do it now? - self.len = 0; + // this is a mem::forget safety thing. If Drain is forgotten, we just + // leak the whole Vec's contents. Also we need to do this *eventually* + // anyway, so why not do it now? + self.len = 0; - Drain { - iter: iter, - vec: PhantomData, - } + Drain { + iter, + vec: PhantomData, } } } diff --git a/src/doc/nomicon/src/vec/vec-final.md b/src/doc/nomicon/src/vec/vec-final.md index e680e0d65..1f73036d8 100644 --- a/src/doc/nomicon/src/vec/vec-final.md +++ b/src/doc/nomicon/src/vec/vec-final.md @@ -127,7 +127,7 @@ impl<T> Vec<T> { pub fn insert(&mut self, index: usize, elem: T) { assert!(index <= self.len, "index out of bounds"); - if self.cap() == self.len { + if self.len == self.cap() { self.buf.grow(); } @@ -138,14 +138,17 @@ impl<T> Vec<T> { self.len - index, ); ptr::write(self.ptr().add(index), elem); - self.len += 1; } + + self.len += 1; } pub fn remove(&mut self, index: usize) -> T { assert!(index < self.len, "index out of bounds"); + + self.len -= 1; + unsafe { - self.len -= 1; let result = ptr::read(self.ptr().add(index)); ptr::copy( self.ptr().add(index + 1), @@ -157,18 +160,16 @@ impl<T> Vec<T> { } pub fn drain(&mut self) -> Drain<T> { - unsafe { - let iter = RawValIter::new(&self); + let iter = unsafe { RawValIter::new(&self) }; - // this is a mem::forget safety thing. If Drain is forgotten, we just - // leak the whole Vec's contents. Also we need to do this *eventually* - // anyway, so why not do it now? - self.len = 0; + // this is a mem::forget safety thing. If Drain is forgotten, we just + // leak the whole Vec's contents. Also we need to do this *eventually* + // anyway, so why not do it now? + self.len = 0; - Drain { - iter: iter, - vec: PhantomData, - } + Drain { + iter, + vec: PhantomData, } } } @@ -197,15 +198,15 @@ impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(self) -> IntoIter<T> { - unsafe { - let iter = RawValIter::new(&self); - let buf = ptr::read(&self.buf); - mem::forget(self); + let (iter, buf) = unsafe { + (RawValIter::new(&self), ptr::read(&self.buf)) + }; - IntoIter { - iter: iter, - _buf: buf, - } + mem::forget(self); + + IntoIter { + iter, + _buf: buf, } } } diff --git a/src/doc/nomicon/src/vec/vec-insert-remove.md b/src/doc/nomicon/src/vec/vec-insert-remove.md index 722e20c45..2acee65ee 100644 --- a/src/doc/nomicon/src/vec/vec-insert-remove.md +++ b/src/doc/nomicon/src/vec/vec-insert-remove.md @@ -18,7 +18,7 @@ pub fn insert(&mut self, index: usize, elem: T) { // Note: `<=` because it's valid to insert after everything // which would be equivalent to push. assert!(index <= self.len, "index out of bounds"); - if self.cap == self.len { self.grow(); } + if self.len == self.cap { self.grow(); } unsafe { // ptr::copy(src, dest, len): "copy from src to dest len elems" @@ -28,8 +28,9 @@ pub fn insert(&mut self, index: usize, elem: T) { self.len - index, ); ptr::write(self.ptr.as_ptr().add(index), elem); - self.len += 1; } + + self.len += 1; } ``` diff --git a/src/doc/nomicon/src/vec/vec-into-iter.md b/src/doc/nomicon/src/vec/vec-into-iter.md index a3a3c8cb9..ad22ff985 100644 --- a/src/doc/nomicon/src/vec/vec-into-iter.md +++ b/src/doc/nomicon/src/vec/vec-into-iter.md @@ -68,18 +68,16 @@ impl<T> IntoIterator for Vec<T> { let cap = vec.cap; let len = vec.len; - unsafe { - IntoIter { - buf: ptr, - cap: cap, - start: ptr.as_ptr(), - end: if cap == 0 { - // can't offset off this pointer, it's not allocated! - ptr.as_ptr() - } else { - ptr.as_ptr().add(len) - }, - } + IntoIter { + buf: ptr, + cap, + start: ptr.as_ptr(), + end: if cap == 0 { + // can't offset off this pointer, it's not allocated! + ptr.as_ptr() + } else { + unsafe { ptr.as_ptr().add(len) } + }, } } } diff --git a/src/doc/nomicon/src/vec/vec-layout.md b/src/doc/nomicon/src/vec/vec-layout.md index 9129952a5..695485f34 100644 --- a/src/doc/nomicon/src/vec/vec-layout.md +++ b/src/doc/nomicon/src/vec/vec-layout.md @@ -40,7 +40,6 @@ we get the same results as using `Unique<T>`: ```rust use std::ptr::NonNull; -use std::marker::PhantomData; pub struct Vec<T> { ptr: NonNull<T>, diff --git a/src/doc/nomicon/src/vec/vec-raw.md b/src/doc/nomicon/src/vec/vec-raw.md index 0bca2daf8..a251b4af3 100644 --- a/src/doc/nomicon/src/vec/vec-raw.md +++ b/src/doc/nomicon/src/vec/vec-raw.md @@ -131,23 +131,21 @@ impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(self) -> IntoIter<T> { - unsafe { - // need to use ptr::read to unsafely move the buf out since it's - // not Copy, and Vec implements Drop (so we can't destructure it). - let buf = ptr::read(&self.buf); - let len = self.len; - mem::forget(self); - - IntoIter { - start: buf.ptr.as_ptr(), - end: if buf.cap == 0 { - // can't offset off of a pointer unless it's part of an allocation - buf.ptr.as_ptr() - } else { - buf.ptr.as_ptr().add(len) - }, - _buf: buf, - } + // need to use ptr::read to unsafely move the buf out since it's + // not Copy, and Vec implements Drop (so we can't destructure it). + let buf = unsafe { ptr::read(&self.buf) }; + let len = self.len; + mem::forget(self); + + IntoIter { + start: buf.ptr.as_ptr(), + end: if buf.cap == 0 { + // can't offset off of a pointer unless it's part of an allocation + buf.ptr.as_ptr() + } else { + unsafe { buf.ptr.as_ptr().add(len) } + }, + _buf: buf, } } } |