docs: remove mentions of Gc.
This commit is contained in:
parent
39de8464ed
commit
aa0b350c97
5 changed files with 20 additions and 110 deletions
|
@ -632,19 +632,6 @@ This part is coming soon.
|
||||||
|
|
||||||
This part is coming soon.
|
This part is coming soon.
|
||||||
|
|
||||||
# Gc
|
|
||||||
|
|
||||||
The `Gc<T>` type exists for historical reasons, and is [still used
|
|
||||||
internally](https://github.com/rust-lang/rust/issues/7929) by the compiler.
|
|
||||||
It is not even a 'real' garbage collected type at the moment.
|
|
||||||
|
|
||||||
In the future, Rust may have a real garbage collected type, and so it
|
|
||||||
has not yet been removed for that reason.
|
|
||||||
|
|
||||||
## Best practices
|
|
||||||
|
|
||||||
There is currently no legitimate use case for the `Gc<T>` type.
|
|
||||||
|
|
||||||
# Raw Pointers
|
# Raw Pointers
|
||||||
|
|
||||||
This part is coming soon.
|
This part is coming soon.
|
||||||
|
|
|
@ -31,7 +31,6 @@ list):
|
||||||
* Task synchronization
|
* Task synchronization
|
||||||
* Task-local storage
|
* Task-local storage
|
||||||
* Logging
|
* Logging
|
||||||
* Local heaps (GC heaps)
|
|
||||||
* Task unwinding
|
* Task unwinding
|
||||||
|
|
||||||
## What is the runtime accomplishing?
|
## What is the runtime accomplishing?
|
||||||
|
|
|
@ -208,9 +208,7 @@ pub struct Unique<T> {
|
||||||
// Implement methods for creating and using the values in the box.
|
// Implement methods for creating and using the values in the box.
|
||||||
|
|
||||||
// NB: For simplicity and correctness, we require that T has kind Send
|
// NB: For simplicity and correctness, we require that T has kind Send
|
||||||
// (owned boxes relax this restriction, and can contain managed (GC) boxes).
|
// (owned boxes relax this restriction).
|
||||||
// This is because, as implemented, the garbage collector would not know
|
|
||||||
// about any shared boxes stored in the malloc'd region of memory.
|
|
||||||
impl<T: Send> Unique<T> {
|
impl<T: Send> Unique<T> {
|
||||||
pub fn new(value: T) -> Unique<T> {
|
pub fn new(value: T) -> Unique<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -3381,7 +3381,7 @@ fn main() {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Patterns can also dereference pointers by using the `&`, `box` or `@` symbols,
|
Patterns can also dereference pointers by using the `&`, `box` symbols,
|
||||||
as appropriate. For example, these two matches on `x: &int` are equivalent:
|
as appropriate. For example, these two matches on `x: &int` are equivalent:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -74,7 +74,7 @@ to an `LV` of `(*a).f`.
|
||||||
Here is the formal grammar for the types we'll consider:
|
Here is the formal grammar for the types we'll consider:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY | @ MQ TY
|
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY
|
||||||
MQ = mut | imm | const
|
MQ = mut | imm | const
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -263,9 +263,7 @@ compatible with the aliasability of `LV`. The goal is to prevent
|
||||||
`&mut` borrows of aliasability data.
|
`&mut` borrows of aliasability data.
|
||||||
|
|
||||||
3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
|
3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
|
||||||
the lifetime of the value being borrowed. This pass is also
|
the lifetime of the value being borrowed.
|
||||||
responsible for inserting root annotations to keep managed values
|
|
||||||
alive.
|
|
||||||
|
|
||||||
4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
|
4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
|
||||||
restrictions to maintain memory safety. These are the restrictions
|
restrictions to maintain memory safety. These are the restrictions
|
||||||
|
@ -316,17 +314,13 @@ MUTABILITY(*LV, MQ) // M-Deref-Unique
|
||||||
|
|
||||||
### Checking mutability of immutable pointer types
|
### Checking mutability of immutable pointer types
|
||||||
|
|
||||||
Immutable pointer types like `&T` and `@T` can only
|
Immutable pointer types like `&T` can only
|
||||||
be borrowed if MQ is immutable or const:
|
be borrowed if MQ is immutable or const:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
|
MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
|
||||||
TYPE(LV) = &Ty
|
TYPE(LV) = &Ty
|
||||||
MQ == imm | const
|
MQ == imm | const
|
||||||
|
|
||||||
MUTABILITY(*LV, MQ) // M-Deref-Managed-Imm
|
|
||||||
TYPE(LV) = @Ty
|
|
||||||
MQ == imm | const
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Checking mutability of mutable pointer types
|
### Checking mutability of mutable pointer types
|
||||||
|
@ -390,11 +384,10 @@ ALIASABLE(*LV, MQ) // M-Deref-Borrowed-Mut
|
||||||
## Checking lifetime
|
## Checking lifetime
|
||||||
|
|
||||||
These rules aim to ensure that no data is borrowed for a scope that exceeds
|
These rules aim to ensure that no data is borrowed for a scope that exceeds
|
||||||
its lifetime. In addition, these rules manage the rooting of `@` values.
|
its lifetime. These two computations wind up being intimately related.
|
||||||
These two computations wind up being intimately related. Formally, we define
|
Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that
|
||||||
a predicate `LIFETIME(LV, LT, MQ)`, which states that "the lvalue `LV` can be
|
"the lvalue `LV` can be safely borrowed for the lifetime `LT` with mutability
|
||||||
safely borrowed for the lifetime `LT` with mutability `MQ`". The Rust
|
`MQ`". The Rust code corresponding to this predicate is the module
|
||||||
code corresponding to this predicate is the module
|
|
||||||
`middle::borrowck::gather_loans::lifetime`.
|
`middle::borrowck::gather_loans::lifetime`.
|
||||||
|
|
||||||
### The Scope function
|
### The Scope function
|
||||||
|
@ -423,14 +416,6 @@ the pointer itself `LV` goes out of scope:
|
||||||
SCOPE(*LV) = SCOPE(LV) if LV has type Box<T>
|
SCOPE(*LV) = SCOPE(LV) if LV has type Box<T>
|
||||||
```
|
```
|
||||||
|
|
||||||
The scope of a managed referent is also the scope of the pointer. This
|
|
||||||
is a conservative approximation, since there may be other aliases for
|
|
||||||
that same managed box that would cause it to live longer:
|
|
||||||
|
|
||||||
```text
|
|
||||||
SCOPE(*LV) = SCOPE(LV) if LV has type @T
|
|
||||||
```
|
|
||||||
|
|
||||||
The scope of a borrowed referent is the scope associated with the
|
The scope of a borrowed referent is the scope associated with the
|
||||||
pointer. This is a conservative approximation, since the data that
|
pointer. This is a conservative approximation, since the data that
|
||||||
the pointer points at may actually live longer:
|
the pointer points at may actually live longer:
|
||||||
|
@ -477,59 +462,6 @@ LIFETIME(*LV, LT, MQ) // L-Deref-Borrowed
|
||||||
LT <= LT'
|
LT <= LT'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Checking lifetime for derefs of managed, immutable pointers
|
|
||||||
|
|
||||||
Managed pointers are valid so long as the data within them is
|
|
||||||
*rooted*. There are two ways that this can be achieved. The first is
|
|
||||||
when the user guarantees such a root will exist. For this to be true,
|
|
||||||
three conditions must be met:
|
|
||||||
|
|
||||||
```text
|
|
||||||
LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-User-Root
|
|
||||||
TYPE(LV) = @Ty
|
|
||||||
LT <= SCOPE(LV) // (1)
|
|
||||||
LV is immutable // (2)
|
|
||||||
LV is not moved or not movable // (3)
|
|
||||||
```
|
|
||||||
|
|
||||||
Condition (1) guarantees that the managed box will be rooted for at
|
|
||||||
least the lifetime `LT` of the borrow, presuming that no mutation or
|
|
||||||
moves occur. Conditions (2) and (3) then serve to guarantee that the
|
|
||||||
value is not mutated or moved. Note that lvalues are either
|
|
||||||
(ultimately) owned by a local variable, in which case we can check
|
|
||||||
whether that local variable is ever moved in its scope, or they are
|
|
||||||
owned by the referent of an (immutable, due to condition 2) managed or
|
|
||||||
references, in which case moves are not permitted because the
|
|
||||||
location is aliasable.
|
|
||||||
|
|
||||||
If the conditions of `L-Deref-Managed-Imm-User-Root` are not met, then
|
|
||||||
there is a second alternative. The compiler can attempt to root the
|
|
||||||
managed pointer itself. This permits great flexibility, because the
|
|
||||||
location `LV` where the managed pointer is found does not matter, but
|
|
||||||
there are some limitations. The lifetime of the borrow can only extend
|
|
||||||
to the innermost enclosing loop or function body. This guarantees that
|
|
||||||
the compiler never requires an unbounded amount of stack space to
|
|
||||||
perform the rooting; if this condition were violated, the compiler
|
|
||||||
might have to accumulate a list of rooted objects, for example if the
|
|
||||||
borrow occurred inside the body of a loop but the scope of the borrow
|
|
||||||
extended outside the loop. More formally, the requirement is that
|
|
||||||
there is no path starting from the borrow that leads back to the
|
|
||||||
borrow without crossing the exit from the scope `LT`.
|
|
||||||
|
|
||||||
The rule for compiler rooting is as follows:
|
|
||||||
|
|
||||||
```text
|
|
||||||
LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-Compiler-Root
|
|
||||||
TYPE(LV) = @Ty
|
|
||||||
LT <= innermost enclosing loop/func
|
|
||||||
ROOT LV at *LV for LT
|
|
||||||
```
|
|
||||||
|
|
||||||
Here I have written `ROOT LV at *LV FOR LT` to indicate that the code
|
|
||||||
makes a note in a side-table that the box `LV` must be rooted into the
|
|
||||||
stack when `*LV` is evaluated, and that this root can be released when
|
|
||||||
the scope `LT` exits.
|
|
||||||
|
|
||||||
## Computing the restrictions
|
## Computing the restrictions
|
||||||
|
|
||||||
The final rules govern the computation of *restrictions*, meaning that
|
The final rules govern the computation of *restrictions*, meaning that
|
||||||
|
@ -599,22 +531,18 @@ RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer
|
||||||
RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS
|
RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS
|
||||||
```
|
```
|
||||||
|
|
||||||
### Restrictions for loans of immutable managed/borrowed referents
|
### Restrictions for loans of immutable borrowed referents
|
||||||
|
|
||||||
Immutable managed/borrowed referents are freely aliasable, meaning that
|
Immutable borrowed referents are freely aliasable, meaning that
|
||||||
the compiler does not prevent you from copying the pointer. This
|
the compiler does not prevent you from copying the pointer. This
|
||||||
implies that issuing restrictions is useless. We might prevent the
|
implies that issuing restrictions is useless. We might prevent the
|
||||||
user from acting on `*LV` itself, but there could be another path
|
user from acting on `*LV` itself, but there could be another path
|
||||||
`*LV1` that refers to the exact same memory, and we would not be
|
`*LV1` that refers to the exact same memory, and we would not be
|
||||||
restricting that path. Therefore, the rule for `&Ty` and `@Ty`
|
restricting that path. Therefore, the rule for `&Ty` pointers
|
||||||
pointers always returns an empty set of restrictions, and it only
|
always returns an empty set of restrictions, and it only permits
|
||||||
permits restricting `MUTATE` and `CLAIM` actions:
|
restricting `MUTATE` and `CLAIM` actions:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Managed
|
|
||||||
TYPE(LV) = @Ty
|
|
||||||
ACTIONS subset of [MUTATE, CLAIM]
|
|
||||||
|
|
||||||
RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed
|
RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed
|
||||||
TYPE(LV) = <' Ty
|
TYPE(LV) = <' Ty
|
||||||
LT <= LT' // (1)
|
LT <= LT' // (1)
|
||||||
|
@ -623,8 +551,8 @@ RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed
|
||||||
|
|
||||||
The reason that we can restrict `MUTATE` and `CLAIM` actions even
|
The reason that we can restrict `MUTATE` and `CLAIM` actions even
|
||||||
without a restrictions list is that it is never legal to mutate nor to
|
without a restrictions list is that it is never legal to mutate nor to
|
||||||
borrow mutably the contents of a `&Ty` or `@Ty` pointer. In other
|
borrow mutably the contents of a `&Ty` pointer. In other words,
|
||||||
words, those restrictions are already inherent in the type.
|
those restrictions are already inherent in the type.
|
||||||
|
|
||||||
Clause (1) in the rule for `&Ty` deserves mention. Here I
|
Clause (1) in the rule for `&Ty` deserves mention. Here I
|
||||||
specify that the lifetime of the loan must be less than the lifetime
|
specify that the lifetime of the loan must be less than the lifetime
|
||||||
|
@ -729,13 +657,12 @@ are affine.)
|
||||||
Freeze pointers are read-only. There may be `&mut` or `&` aliases, and
|
Freeze pointers are read-only. There may be `&mut` or `&` aliases, and
|
||||||
we can not prevent *anything* but moves in that case. So the
|
we can not prevent *anything* but moves in that case. So the
|
||||||
`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
|
`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
|
||||||
Because moves from a `&const` or `@const` lvalue are never legal, it
|
Because moves from a `&const` lvalue are never legal, it is not
|
||||||
is not necessary to add any restrictions at all to the final
|
necessary to add any restrictions at all to the final result.
|
||||||
result.
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed
|
RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed
|
||||||
TYPE(LV) = &const Ty or @const Ty
|
TYPE(LV) = &const Ty
|
||||||
```
|
```
|
||||||
|
|
||||||
### Restrictions for loans of mutable borrowed referents
|
### Restrictions for loans of mutable borrowed referents
|
||||||
|
@ -957,8 +884,7 @@ moves and the declaration of uninitialized variables. For each of
|
||||||
these points, we create a bit in the dataflow set. Assignments to a
|
these points, we create a bit in the dataflow set. Assignments to a
|
||||||
variable `x` or path `a.b.c` kill the move/uninitialization bits for
|
variable `x` or path `a.b.c` kill the move/uninitialization bits for
|
||||||
those paths and any subpaths (e.g., `x`, `x.y`, `a.b.c`, `*a.b.c`).
|
those paths and any subpaths (e.g., `x`, `x.y`, `a.b.c`, `*a.b.c`).
|
||||||
The bits are also killed when the root variables (`x`, `a`) go out of
|
Bits are unioned when two control-flow paths join. Thus, the
|
||||||
scope. Bits are unioned when two control-flow paths join. Thus, the
|
|
||||||
presence of a bit indicates that the move may have occurred without an
|
presence of a bit indicates that the move may have occurred without an
|
||||||
intervening assignment to the same memory. At each use of a variable,
|
intervening assignment to the same memory. At each use of a variable,
|
||||||
we examine the bits in scope, and check that none of them are
|
we examine the bits in scope, and check that none of them are
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue