summaryrefslogtreecommitdiffstats
path: root/src/doc/nomicon
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /src/doc/nomicon
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-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.md35
-rw-r--r--src/doc/nomicon/src/races.md33
-rw-r--r--src/doc/nomicon/src/vec/vec-drain.md20
-rw-r--r--src/doc/nomicon/src/vec/vec-final.md43
-rw-r--r--src/doc/nomicon/src/vec/vec-insert-remove.md5
-rw-r--r--src/doc/nomicon/src/vec/vec-into-iter.md22
-rw-r--r--src/doc/nomicon/src/vec/vec-layout.md1
-rw-r--r--src/doc/nomicon/src/vec/vec-raw.md32
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,
}
}
}