Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document RFC 1440. #166

Merged
merged 2 commits into from
Dec 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,25 +209,25 @@ then it is a compiler error if the value must be evaluated at compile time,
otherwise it is just a warning, but the code will most likely panic when run.

The following expressions are constant expressions, so long as any operands are
also constant expressions:
also constant expressions and do not cause any [`Drop::drop`][destructors] calls
to be ran.

* [Literals].
* [Paths] to [functions](items/functions.html) and constants.
Recursively defining constants is not allowed.
* [Tuple expressions].
* [Array expressions].
* [Struct] expressions, where the type does not implement [`Drop`](the-drop-trait.html).
* [Enum variant] expressions, where the enumeration type does not implement `Drop`.
* [Block expressions] (and `unsafe` blocks) which only contain items and
possibly a (constant) tail expression.
* [Struct] expressions.
* [Enum variant] expressions.
* [Block expressions], including `unsafe` blocks, which only contain items and
possibly a constant tail expression.
* [Field] expressions.
* Index expressions, [array indexing] or [slice] with a `usize`.
* [Range expressions].
* [Closure expressions] which don't capture variables from the environment.
* Built in [negation], [arithmetic, logical], [comparison] or [lazy boolean]
operators used on integer and floating point types, `bool` and `char`.
* Shared [borrow], except if applied to a type with [interior
mutability](interior-mutability.html).
* Shared [borrow]s, except if applied to a type with [interior mutability].
* The [dereference operator].
* [Grouped] expressions.
* [Cast] expressions, except pointer to address and
Expand Down Expand Up @@ -269,4 +269,6 @@ exist in `core::ops` and `core::cmp` with the same names.
[negation]: expressions/operator-expr.html#negation-operators
[overflow]: expressions/operator-expr.html#overflow

[destructors]: destructors.html
[interior-mutability]: interior-mutability.html
[slice]: types.html#array-and-slice-types
6 changes: 3 additions & 3 deletions src/interior-mutability.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Interior Mutability

Sometimes a type needs be mutated while having multiple aliases, in Rust this
Sometimes a type needs be mutated while having multiple aliases. In Rust this
is achieved using a pattern called _interior mutability_. A type has interior
mutability if its internal state can be changed through a [shared reference] to
it. This goes against the usual [requirement][ub] that the value pointed to by a
shared reference is not mutated.

[`std::cell::UnsafeCell<T>`] type is the only legal way in Rust to disable this
requirement. When `UnsafeCell<T>` is immutably aliased, it is still safe to
[`std::cell::UnsafeCell<T>`] type is the only allowed way in Rust to disable
this requirement. When `UnsafeCell<T>` is immutably aliased, it is still safe to
mutate, or obtain a mutable reference to, the `T` it contains. As with all
other types, it is undefined behavior to have multiple `&mut UnsafeCell<T>`
aliases.
Expand Down
35 changes: 28 additions & 7 deletions src/items/constant-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ wherever they are used, meaning that they are copied directly into the relevant
context when used. References to the same constant are not necessarily
guaranteed to refer to the same memory address.

Constant values must not have destructors, and otherwise permit most forms of
data. Constants may refer to the address of other constants, in which case the
Constants must be explicitly typed. The type must have a `'static` lifetime: any
references it contains must have `'static` lifetimes.

Constants may refer to the address of other constants, in which case the
address will have elided lifetimes where applicable, otherwise – in most cases
– defaulting to the `static` lifetime. (See below on [static lifetime
– defaulting to the `static` lifetime. (See [static lifetime
elision].) The compiler is, however, still at liberty to translate the constant
many times, so the address referred to may not be stable.

Constants must be explicitly typed. The type may be any type that doesn't
implement [`Drop`] and has a `'static` lifetime: any references it contains
must have `'static` lifetimes.

```rust
const BIT1: u32 = 1 << 0;
const BIT2: u32 = 1 << 1;
Expand All @@ -39,6 +37,29 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
};
```

## Constants with Destructors

Constants can contain destructors. Destructors are ran when the value goes out
of scope.

```rust
struct TypeWithDestructor(i32);

impl Drop for TypeWithDestructor {
fn drop(&mut self) {
println!("Dropped. Held {}.", self.0);
}
}

const ZERO_WITH_DESTRUCTOR: TypeWithDestructor = TypeWithDestructor(0);

fn create_and_drop_zero_with_destructor() {
let x = ZERO_WITH_DESTRUCTOR;
// x gets dropped at end of function, calling drop.
// prints "Dropped. Held 0.".
}
```

[constant value]: expressions.html#constant-expressions
[static lifetime elision]: items/static-items.html#static-lifetime-elision
[`Drop`]: the-drop-trait.html
Expand Down
36 changes: 20 additions & 16 deletions src/items/static-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,23 @@
> &nbsp;&nbsp; `static` `mut`<sup>?</sup> [IDENTIFIER] `:` [_Type_]
> `=` [_Expression_] `;`

A *static item* is similar to a *constant*, except that it represents a precise
A *static item* is similar to a [constant], except that it represents a precise
memory location in the program. A static is never "inlined" at the usage site,
and all references to it refer to the same memory location. Static items have
the `static` lifetime, which outlives all other lifetimes in a Rust program.
Static items may be placed in read-only memory if they do not contain any
interior mutability.
Static items may be placed in read-only memory if the type is not [interior
mutable]. Static items do not call `drop` at the end of the program.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we ever used "interior mutable" as an adjective before? I always thought the term was always "interior mutability", as a noun.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we do, but it is a natural analog to interior mutability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a shame "interiorally" isn't a word, otherwise that's what i would suggest. With our conversation on IRC, i'm willing to call this okay. Farther bikeshedding of how to decline "interior mutability" can occur elsewhere.


Statics may contain interior mutability through the `UnsafeCell` language item.
All access to a static is safe, but there are a number of restrictions on
statics:

* Statics may not contain any destructors.
* The types of static values must ascribe to `Sync` to allow thread-safe
access.
* The type must have the `Sync` trait bound to allow thread-safe access.
* Statics allow using paths to statics in the
[constant-expression](expressions.html#constant-expressions) used to
initialize them, but statics may not refer to other statics by value, only by
reference.
initialize them, but statics may not refer to other statics by value, only
through a reference.
* Constants cannot refer to statics.

Constants should in general be preferred over statics, unless large amounts of
data are being stored, or single-address and mutability properties are
required.

## Mutable statics

If a static item is declared with the `mut` keyword, then it is allowed to be
Expand Down Expand Up @@ -64,7 +57,7 @@ unsafe fn bump_levels_unsafe2() -> u32 {
```

Mutable statics have the same restrictions as normal statics, except that the
type of the value is not required to ascribe to `Sync`.
type does not have to implement the `Sync` trait.

## `'static` lifetime elision

Expand Down Expand Up @@ -97,8 +90,6 @@ the standard elision rules ([see discussion in the nomicon][elision-nomicon]).
If it is unable to resolve the lifetimes by its usual rules, it will default to
using the `'static` lifetime. By way of example:

[elision-nomicon]: ../nomicon/lifetime-elision.html

```rust,ignore
// Resolved as `fn<'a>(&'a str) -> &'a str`.
const RESOLVED_SINGLE: fn(&str) -> &str = ..
Expand All @@ -112,6 +103,19 @@ const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
```

## Using Statics or Consts

In can be confusing whether or not you should use a constant item or a static
item. Constants should, in general, be preferred over statics unless one of the
following are true:

* Large amounts of data are being stored
* The single-address or non-inlining property of statics is required.
* Interior mutability is required.

[constant]: items/constant-items.html
[interior mutable]: interior_mutability.html
[IDENTIFIER]: identifiers.html
[_Type_]: types.html
[_Expression_]: expressions.html
[elision-nomicon]: ../nomicon/lifetime-elision.html