diff options
| author | kennytm <kennytm@gmail.com> | 2018-03-13 00:54:24 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-03-13 00:54:24 +0800 |
| commit | fdb5181f25fd79720cde21e0e4bb231d91a76d68 (patch) | |
| tree | 0395697eea39b02f96a8f945b554c8a0d8d0a230 | |
| parent | 883e74645d350b6752cb94d48f46363f6f8789e9 (diff) | |
| parent | 55be28367413e01262e4fb72d4af36cee368b65d (diff) | |
| download | rust-fdb5181f25fd79720cde21e0e4bb231d91a76d68.tar.gz rust-fdb5181f25fd79720cde21e0e4bb231d91a76d68.zip | |
Rollup merge of #48201 - NovemberZulu:master, r=steveklabnik
rephrase UnsafeCell doc As shown by discussions on users.rust-lang.org [[1]], [[2]], UnsafeCell doc is not totally clear. I tried to made the doc univocal regarding what is allowed and what is not. The edits are based on my understanding following [[1]]. [1]: https://users.rust-lang.org/t/unsafecell-behavior-details/1560 [2]: https://users.rust-lang.org/t/is-there-a-better-way-to-overload-index-indexmut-for-a-rc-refcell/15591/12
| -rw-r--r-- | src/libcore/cell.rs | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1372151b753..36618e86968 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1203,21 +1203,42 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered /// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior. /// -/// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or -/// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, -/// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way -/// to do this. When `UnsafeCell<T>` is immutably aliased, it is still safe to obtain a mutable -/// reference to its interior and/or to mutate it. However, it is up to the abstraction designer -/// to ensure that no two mutable references obtained this way are active at the same time, and -/// that there are no active mutable references or mutations when an immutable reference is obtained -/// from the cell. This is often done via runtime checks. +/// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are +/// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably +/// aliased or mutated, and that `&mut T` is unique. `UnsafeCel<T>` is the only core language +/// feature to work around this restriction. All other types that allow internal mutability, such as +/// `Cell<T>` and `RefCell<T>` use `UnsafeCell` to wrap their internal data. /// -/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell<T>` is -/// okay (provided you enforce the invariants some other way); it is still undefined behavior -/// to have multiple `&mut UnsafeCell<T>` aliases. +/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to +/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// +/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: +/// +/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference) that +/// is accessible by safe code (for example, because you returned it), then you must not access +/// the data in any way that contradicts that reference for the remainder of `'a`. For example, that +/// means that if you take the `*mut T` from an `UnsafeCell<T>` and case it to an `&T`, then until +/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any +/// `UnsafeCell` data found within `T`, of course). Similarly, if you create an `&mut T` reference +/// that is released to safe code, then you must not access the data within the `UnsafeCell` until +/// that reference expires. +/// +/// - At all times, you must avoid data races, meaning that if multiple threads have access to +/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other +/// accesses (or use atomics). /// +/// To assist with proper design, the following scenarios are explicitly declared legal +/// for single-threaded code: /// -/// Types like `Cell<T>` and `RefCell<T>` use this type to wrap their internal data. +/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` +/// references, but not with a `&mut T` +/// +/// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` +/// co-exist with it. A `&mut T` must always be unique. +/// +/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell<T>` is +/// okay (provided you enforce the invariants some other way), it is still undefined behavior +/// to have multiple `&mut UnsafeCell<T>` aliases. /// /// # Examples /// @@ -1282,9 +1303,9 @@ impl<T: ?Sized> UnsafeCell<T> { /// Gets a mutable pointer to the wrapped value. /// /// This can be cast to a pointer of any kind. - /// Ensure that the access is unique when casting to - /// `&mut T`, and ensure that there are no mutations or mutable - /// aliases going on when casting to `&T` + /// Ensure that the access is unique (no active references, mutable or not) + /// when casting to `&mut T`, and ensure that there are no mutations + /// or mutable aliases going on when casting to `&T` /// /// # Examples /// |
